Unstable 1.8.4.0

This commit is contained in:
Markus Isberg
2025-03-12 12:56:27 +00:00
parent a4c3e868e4
commit a4a3427e4e
627 changed files with 29860 additions and 10018 deletions
@@ -4,15 +4,18 @@ using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using FarseerPhysics.Dynamics;
using static Barotrauma.AIObjectiveFindSafety;
using System.Collections.Immutable;
using System.Diagnostics;
using FarseerPhysics;
namespace Barotrauma
{
class AIObjectiveCombat : AIObjective
{
public override Identifier Identifier { get; set; } = "combat".ToIdentifier();
public override string DebugTag => $"{Identifier} ({Mode})";
public override bool KeepDivingGearOn => true;
public override bool IgnoreUnsafeHulls => true;
@@ -35,10 +38,9 @@ namespace Barotrauma
private bool allowCooldown;
public Character Enemy { get; private set; }
public bool HoldPosition { get; set; }
private Item _weapon;
private Item Weapon
public Item Weapon
{
get { return _weapon; }
set
@@ -48,6 +50,7 @@ namespace Barotrauma
}
}
private ItemComponent _weaponComponent;
private bool hasValidRangedWeapon;
private ItemComponent WeaponComponent
{
get
@@ -74,7 +77,6 @@ namespace Barotrauma
private float pathBackTimer;
private const float DefaultCoolDown = 10.0f;
private const float PathBackCheckTime = 1.0f;
private IEnumerable<Body> myBodies;
private float aimTimer;
private float reloadTimer;
private float spreadTimer;
@@ -88,7 +90,9 @@ namespace Barotrauma
private const float DistanceCheckInterval = 0.2f;
private float distanceTimer;
private const float CloseDistanceThreshold = 300;
private const float CloseDistance = 300;
private const float MeleeDistance = 125;
private const float TooCloseToShoot = 100;
private const float FloorHeightApproximate = 100;
public bool AllowHoldFire;
@@ -169,13 +173,7 @@ namespace Barotrauma
public AIObjectiveCombat(Character character, Character enemy, CombatMode mode, AIObjectiveManager objectiveManager, float priorityModifier = 1, float coolDown = DefaultCoolDown)
: base(character, objectiveManager, priorityModifier)
{
if (mode == CombatMode.None)
{
#if DEBUG
DebugConsole.ThrowError("Combat mode == None");
#endif
return;
}
Debug.Assert(mode != CombatMode.None);
Enemy = enemy;
coolDownTimer = coolDown;
findSafety = objectiveManager.GetObjective<AIObjectiveFindSafety>();
@@ -230,6 +228,7 @@ namespace Barotrauma
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isAimBlocked = false;
ignoreWeaponTimer -= deltaTime;
checkWeaponsTimer -= deltaTime;
if (reloadTimer > 0)
@@ -257,7 +256,7 @@ namespace Barotrauma
}
}
protected override bool CheckObjectiveSpecific()
protected override bool CheckObjectiveState()
{
if (character.Submarine is { TeamID: CharacterTeamType.FriendlyNPC } && character.Submarine == Enemy.Submarine)
{
@@ -332,68 +331,155 @@ namespace Barotrauma
pathBackTimer -= deltaTime;
}
}
if (standUpTimer > 0)
{
standUpTimer -= deltaTime;
}
else
{
// Crouch by default so that others can shoot from behind. Disabled when the line of sight is blocked and while moving.
allowCrouching = true;
}
if (HumanAIController.DebugAI)
{
BlockedPositions ??= new List<Vector2>();
BlockedPositions.Clear();
}
if (seekAmmunitionObjective == null && seekWeaponObjective == null)
{
if (Mode != CombatMode.Retreat && TryArm())
{
OperateWeapon(deltaTime);
}
if (HoldPosition)
{
SteeringManager.Reset();
}
else if (seekAmmunitionObjective == null && seekWeaponObjective == null)
isMoving = false;
if (seekAmmunitionObjective == null && seekWeaponObjective == null)
{
Move(deltaTime);
}
}
}
private bool isMoving;
private void Move(float deltaTime)
{
switch (Mode)
if (Mode == CombatMode.Retreat)
{
case CombatMode.Offensive:
case CombatMode.Arrest:
Retreat(deltaTime);
}
else if (character.IsOnPlayerTeam && !Enemy.IsPlayer && objectiveManager.CurrentOrder is AIObjectiveGoTo gotoObjective)
{
if (gotoObjective.IsWaitOrder && WeaponComponent is MeleeWeapon && IsEnemyClose(CloseDistance))
{
// Ordered to wait near the enemy with a melee weapon -> engage.
Engage(deltaTime);
break;
case CombatMode.Defensive:
if (character.IsOnPlayerTeam && !Enemy.IsPlayer && objectiveManager.IsCurrentOrder<AIObjectiveGoTo>())
}
else
{
// Ordered to follow -> keep following.
if (!gotoObjective.IsCloseEnough)
{
if ((character.CurrentHull == null || character.CurrentHull == Enemy.CurrentHull) && sqrDistance < 200 * 200)
isMoving = true;
}
gotoObjective.FaceTargetOnCompleted = false;
gotoObjective.ForceAct(deltaTime);
if (!character.AnimController.InWater && IsEnemyClose(CloseDistance))
{
// If close to the enemy, face it, so that we can attack it.
HumanAIController.FaceTarget(Enemy);
HumanAIController.AutoFaceMovement = false;
if (!gotoObjective.ShouldRun(true))
{
Engage(deltaTime);
ForceWalk = true;
}
}
}
}
else
{
switch (Mode)
{
case CombatMode.Defensive:
Retreat(deltaTime);
break;
case CombatMode.Offensive when hasValidRangedWeapon && IsEnemyClose(CloseDistance):
// Too close to the enemy -> try to back off.
Hull currentHull = character.CurrentHull;
bool backOff = currentHull != null;
Vector2 escapeVel = Vector2.Zero;
if (backOff)
{
int previousEnemyDir = 0;
foreach (Character enemy in Character.CharacterList)
{
if (!HumanAIController.IsActive(enemy) || HumanAIController.IsFriendly(enemy) || enemy.IsHandcuffed) { continue; }
if (enemy.CurrentHull == null) { continue; }
if (currentHull != enemy.CurrentHull && !currentHull.linkedTo.Contains(enemy.CurrentHull)) { continue; }
Vector2 dir = character.Position - enemy.Position;
int enemyDir = Math.Sign(dir.X);
if (enemyDir == 0)
{
// Exactly at the same pos.
if (previousEnemyDir != 0)
{
// Another enemy at either side -> Ignore this enemy.
continue;
}
else
{
// Just choose either direction.
enemyDir = Rand.Value() > 0.5f ? 1 : -1;
}
}
if (previousEnemyDir != 0 && enemyDir != previousEnemyDir)
{
// Don't back off when there are enemies in different directions, because that's doomed.
backOff = false;
break;
}
previousEnemyDir = enemyDir;
// This formula is slightly modified from AIObjectiveFindSafety.UpdateSimpleEscape().
float distMultiplier = MathHelper.Clamp(MeleeDistance / Vector2.Distance(enemy.Position, character.Position), 0.1f, 10.0f);
escapeVel += new Vector2(enemyDir * distMultiplier, !character.IsClimbing ? 0 : Math.Sign(dir.Y) * distMultiplier);
}
if (escapeVel == Vector2.Zero)
{
backOff = false;
}
if (backOff)
{
// Only move if we haven't reached the edge of the room.
float left = currentHull.Rect.X + 50;
float right = currentHull.Rect.Right - 50;
backOff = escapeVel.X < 0 && character.Position.X > left || escapeVel.X > 0 && character.Position.X < right;
}
}
if (backOff)
{
BackOff();
}
else
{
// Keep following the goto target
var gotoObjective = objectiveManager.GetOrder<AIObjectiveGoTo>();
if (gotoObjective != null)
{
gotoObjective.ForceAct(deltaTime);
if (!character.AnimController.InWater)
{
HumanAIController.FaceTarget(Enemy);
ForceWalk = true;
HumanAIController.AutoFaceMovement = false;
}
}
else
{
SteeringManager.Reset();
}
Engage(deltaTime);
}
}
else
{
Retreat(deltaTime);
}
break;
case CombatMode.Retreat:
Retreat(deltaTime);
break;
default:
throw new NotImplementedException();
void BackOff()
{
RemoveFollowTarget();
isMoving = true;
if (!IsEnemyClose(MeleeDistance))
{
ForceWalk = true;
}
HumanAIController.FaceTarget(Enemy);
HumanAIController.AutoFaceMovement = false;
character.ReleaseSecondaryItem();
character.AIController.SteeringManager.SteeringManual(deltaTime, escapeVel);
}
break;
default:
Engage(deltaTime);
break;
}
}
}
@@ -408,7 +494,8 @@ namespace Barotrauma
bool isAllowedToSeekWeapons = character.IsHostileEscortee || character.IsPrisoner || // Prisoners and terrorists etc are always allowed to seek new weapons.
(character.IsInFriendlySub // Other characters need to be on a friendly sub in order to "know" where the weapons are. This also prevents NPCs "stealing" player items.
&& IsOffensiveOrArrest // = Defensive or retreating AI shouldn't seek new weapons.
&& !character.IsInstigator); // Instigators (= aggressive NPCs spawned with events) shouldn't seek new weapons, because we don't want them to grab e.g. an smg, if they spawn with a wrench or something.
&& !character.IsInstigator // Instigators (= aggressive NPCs spawned with events) shouldn't seek new weapons, because we don't want them to grab e.g. an smg, if they spawn with a wrench or something.
&& objectiveManager.CurrentOrder is not AIObjectiveGoTo); // if ordered to wait/follow, shouldn't go seeking new weapons.
if (checkWeaponsTimer < 0)
{
checkWeaponsTimer = CheckWeaponsInterval;
@@ -434,7 +521,12 @@ namespace Barotrauma
// All good, the weapon is loaded
break;
}
bool seekAmmo = isAllowedToSeekWeapons && seekAmmunitionObjective == null && !IsEnemyClose(CloseDistanceThreshold);
bool seekAmmo = isAllowedToSeekWeapons && seekAmmunitionObjective == null;
if (seekAmmo)
{
// Bots set to arrest the target are always allowed to seek (or spawn) more ammo, because otherwise they might not be able to stun the target and need to use lethal weapons.
seekAmmo = Mode == CombatMode.Arrest || !IsEnemyClose(CloseDistance);
}
if (Reload(seekAmmo: seekAmmo))
{
// All good, we can use the weapon.
@@ -480,7 +572,7 @@ namespace Barotrauma
Mode = CombatMode.Retreat;
}
}
else if (seekAmmunitionObjective == null && (WeaponComponent == null || (WeaponComponent.CombatPriority < GoodWeaponPriority && !IsEnemyClose(CloseDistanceThreshold))))
else if (seekAmmunitionObjective == null && (WeaponComponent == null || (WeaponComponent.CombatPriority < GoodWeaponPriority && !IsEnemyClose(CloseDistance))))
{
// No weapon or only a poor weapon equipped -> try to find better.
RemoveSubObjective(ref retreatObjective);
@@ -489,7 +581,7 @@ namespace Barotrauma
constructor: () => new AIObjectiveGetItem(character, "weapon".ToIdentifier(), objectiveManager, equip: true, checkInventory: false)
{
AllowStealing = HumanAIController.IsMentallyUnstable,
AbortCondition = obj => IsEnemyClose(200),
AbortCondition = _ => IsEnemyClose(CloseDistance / 2),
EvaluateCombatPriority = false, // Use a custom formula instead
GetItemPriority = i =>
{
@@ -582,6 +674,12 @@ namespace Barotrauma
private void OperateWeapon(float deltaTime)
{
if (isMoving && character.IsClimbing)
{
// Don't climb and shoot at the same time, because it messes up the aiming.
ClearInputs();
return;
}
switch (Mode)
{
case CombatMode.Offensive:
@@ -790,17 +888,22 @@ namespace Barotrauma
return containers.None() || containers.Any(container =>
(container as ItemContainer)?.Inventory.AllItems.Any(i => i != null && i.HasTag(mobileBatteryTag) && i.Condition > 0.0f) ?? false);
}
private Item GetWeapon(IEnumerable<ItemComponent> weaponList, out ItemComponent weaponComponent)
{
hasValidRangedWeapon = false;
weaponComponent = null;
float bestPriority = 0;
float lethalDmg = -1;
bool prioritizeMelee = IsEnemyClose(50) || EnemyAIController.IsLatchedTo(Enemy, character);
bool isCloseToEnemy = prioritizeMelee || IsEnemyClose(CloseDistanceThreshold);
foreach (var weapon in weaponList)
bool prioritizeMelee = IsEnemyClose(TooCloseToShoot) || EnemyAIController.IsLatchedTo(Enemy, character);
bool isCloseToEnemy = prioritizeMelee || IsEnemyClose(CloseDistance);
foreach (ItemComponent weapon in weaponList)
{
float priority = GetWeaponPriority(weapon, prioritizeMelee, canSeekAmmo: !isCloseToEnemy, out lethalDmg);
if (priority >= GoodWeaponPriority && weapon is RangedWeapon or RepairTool)
{
hasValidRangedWeapon = true;
}
if (priority > bestPriority)
{
weaponComponent = weapon;
@@ -898,23 +1001,13 @@ namespace Barotrauma
}
}
}
private void Unequip()
private void UnequipWeapon()
{
if (!character.LockHands && character.HeldItems.Contains(Weapon))
{
if (!Weapon.AllowedSlots.Contains(InvSlotType.Any) || !character.Inventory.TryPutItem(Weapon, character, new List<InvSlotType>() { InvSlotType.Any }))
{
if (Weapon.AllowedSlots.Contains(InvSlotType.Bag))
{
if (character.Inventory.TryPutItem(Weapon, character, new List<InvSlotType>() { InvSlotType.Bag }))
{
return;
}
}
Weapon.Drop(character);
}
}
if (Weapon == null) { return; }
if (character.LockHands) { return; }
if (character.HeldItems.Contains(Weapon)) { return; }
character.Unequip(Weapon);
}
private bool Equip()
@@ -929,7 +1022,15 @@ namespace Barotrauma
ClearInputs();
Weapon.TryInteract(character, forceSelectKey: true);
var slots = Weapon.AllowedSlots.Where(CharacterInventory.IsHandSlotType);
if (character.Inventory.TryPutItem(Weapon, character, slots))
bool successfullyEquipped = character.TryPutItem(Weapon, slots);
if (!successfullyEquipped && character.HasHandsFull(out (Item leftHandItem, Item rightHandItem) items))
{
// Unequip and try again.
character.Unequip(items.leftHandItem);
character.Unequip(items.rightHandItem);
successfullyEquipped = character.TryPutItem(Weapon, slots);
}
if (successfullyEquipped)
{
SetAimTimer(Rand.Range(0.2f, 0.4f) / AimSpeed);
SetReloadTime(WeaponComponent);
@@ -950,6 +1051,7 @@ namespace Barotrauma
private void Retreat(float deltaTime)
{
isMoving = true;
if (!Enemy.IsHuman && !character.IsInFriendlySub)
{
// Only relevant when we are retreating from monsters and are not inside a friendly sub.
@@ -1047,6 +1149,7 @@ namespace Barotrauma
{
if (sqrDistance > MathUtils.Pow2(meleeWeapon.Range))
{
isMoving = true;
character.ReleaseSecondaryItem();
// Swim towards the target
SteeringManager.Reset();
@@ -1097,7 +1200,7 @@ namespace Barotrauma
}
});
if (followTargetObjective == null) { return; }
if (Mode == CombatMode.Arrest && Enemy.IsKnockedDown && !arrestingRegistered)
if (Mode == CombatMode.Arrest && Enemy.IsKnockedDownOrRagdolled && !arrestingRegistered)
{
bool hasHandCuffs = HumanAIController.HasItem(character, Tags.HandLockerItem, out _);
if (!hasHandCuffs && character.TeamID == CharacterTeamType.FriendlyNPC)
@@ -1122,12 +1225,20 @@ namespace Barotrauma
followTargetObjective.CloseEnough =
WeaponComponent switch
{
RangedWeapon => 1000,
RangedWeapon => isAimBlocked ? BlockedDistance : 1000,
MeleeWeapon mw => mw.Range,
RepairTool rt => rt.Range,
_ => 50
};
}
if (isAimBlocked)
{
ForceWalk = true;
}
if (!followTargetObjective.IsCloseEnough)
{
isMoving = true;
}
}
private void RemoveFollowTarget()
@@ -1145,19 +1256,23 @@ namespace Barotrauma
private void OnArrestTargetReached()
{
if (!Enemy.IsKnockedDown)
if (!Enemy.IsKnockedDownOrRagdolled)
{
RemoveFollowTarget();
return;
}
if (character.TeamID == CharacterTeamType.FriendlyNPC)
{
// Confiscate stolen goods and all weapons
foreach (var item in Enemy.Inventory.AllItemsMod)
{
// Ignore handcuffs already on the target.
if (item.HasTag(Tags.HandLockerItem) && Enemy.HasEquippedItem(item)) { continue; }
if (item.Illegitimate || item.HasTag(Tags.Weapon) || item.HasTag(Tags.Poison) || GetWeaponComponent(item) is { CombatPriority: > 0 })
AIObjectiveFindThieves.MarkTargetAsInspected(character);
bool confiscateItem = AIObjectiveCheckStolenItems.IsItemIllegitimate(Enemy, item);
if (!confiscateItem && Enemy.IsActingOffensively)
{
// Confiscate any weapons or items that can be used offensively.
confiscateItem = item.HasTag(Tags.Weapon) || item.HasTag(Tags.Poison) || GetWeaponComponent(item) is { CombatPriority: > 0 };
}
if (confiscateItem)
{
item.Drop(character);
character.Inventory.TryPutItem(item, character, CharacterInventory.AnySlot);
@@ -1172,7 +1287,7 @@ namespace Barotrauma
}
if (matchingItems.Any() &&
!Enemy.IsUnconscious && Enemy.IsKnockedDown && character.CanInteractWith(Enemy) && !Enemy.LockHands)
!Enemy.IsUnconscious && Enemy.IsKnockedDownOrRagdolled && character.CanInteractWith(Enemy) && !Enemy.LockHands)
{
var handCuffs = matchingItems.First();
if (!HumanAIController.TakeItem(handCuffs, Enemy.Inventory, equip: true, wear: true))
@@ -1205,7 +1320,8 @@ namespace Barotrauma
RemoveFollowTarget();
var itemContainer = Weapon.GetComponent<ItemContainer>();
TryAddSubObjective(ref seekAmmunitionObjective,
constructor: () => new AIObjectiveContainItem(character, ammunitionIdentifiers, itemContainer, objectiveManager)
constructor: () => new AIObjectiveContainItem(character, ammunitionIdentifiers, itemContainer, objectiveManager,
spawnItemIfNotFound: !character.IsOnPlayerTeam && character.AIController.HasInfiniteItemSpawns(ammunitionIdentifiers))
{
ItemCount = itemContainer.MainContainerCapacity * itemContainer.MaxStackSize,
checkInventory = false,
@@ -1227,10 +1343,9 @@ namespace Barotrauma
/// </summary>
private bool Reload(bool seekAmmo)
{
if (WeaponComponent == null) { return false; }
if (WeaponComponent == null) { return false; }
if (Weapon.OwnInventory == null) { return true; }
// Eject empty ammo
HumanAIController.UnequipEmptyItems(Weapon);
HumanAIController.UnequipEmptyItems(Weapon, allowDestroying: !character.IsOnPlayerTeam);
ImmutableHashSet<Identifier> ammunitionIdentifiers = null;
if (WeaponComponent.RequiredItems.ContainsKey(RelatedItem.RelationType.Contained))
{
@@ -1270,7 +1385,7 @@ namespace Barotrauma
{
return true;
}
else if (!HoldPosition && IsOffensiveOrArrest && seekAmmo && ammunitionIdentifiers != null)
else if (IsOffensiveOrArrest && seekAmmo && ammunitionIdentifiers != null)
{
// Inventory not drawn = it's not interactable
// If the weapon is empty and the inventory is inaccessible, it can't be reloaded
@@ -1280,6 +1395,20 @@ namespace Barotrauma
return false;
}
private bool isAimBlocked;
private float _blockedDistance;
private float BlockedDistance
{
get
{
if (_blockedDistance <= 0)
{
_blockedDistance = CloseDistance * Rand.Range(1.0f, 1.3f);
}
return _blockedDistance;
}
}
public List<Vector2> BlockedPositions;
private void Attack(float deltaTime)
{
character.CursorPosition = Enemy.WorldPosition;
@@ -1322,8 +1451,6 @@ namespace Barotrauma
aimTimer -= deltaTime;
return;
}
if (reloadTimer > 0) { return; }
if (holdFireCondition != null && holdFireCondition()) { return; }
sqrDistance = Vector2.DistanceSquared(character.WorldPosition, Enemy.WorldPosition);
distanceTimer = DistanceCheckInterval;
if (WeaponComponent is MeleeWeapon meleeWeapon)
@@ -1353,9 +1480,11 @@ namespace Barotrauma
if (closeEnough && Enemy.WorldPosition.Y < character.WorldPosition.Y && yDiff > 25)
{
// The target is probably knocked down? -> try to reach it by crouching.
HumanAIController.AnimController.Crouching = true;
HumanAIController.AnimController.Crouch();
}
}
if (reloadTimer > 0) { return; }
if (holdFireCondition != null && holdFireCondition()) { return; }
if (closeEnough)
{
UseWeapon(deltaTime);
@@ -1371,36 +1500,59 @@ namespace Barotrauma
{
if (WeaponComponent is RepairTool repairTool)
{
if (sqrDistance > repairTool.Range * repairTool.Range) { return; }
float reach = AIObjectiveFixLeak.CalculateReach(repairTool, character);
if (sqrDistance > reach * reach) { return; }
}
float aimFactor = MathHelper.PiOver2 * (1 - AimAccuracy);
if (VectorExtensions.Angle(VectorExtensions.Forward(Weapon.body.TransformedRotation), Enemy.WorldPosition - Weapon.WorldPosition) < MathHelper.PiOver4 + aimFactor)
{
myBodies ??= character.AnimController.Limbs.Select(l => l.body.FarseerBody);
// Check that we don't hit friendlies. No need to check the walls, because there's a separate check for that at 1096 (which intentionally has a small delay)
var pickedBodies = Submarine.PickBodies(Weapon.SimPosition, Submarine.GetRelativeSimPosition(from: Weapon, to: Enemy), myBodies, Physics.CollisionCharacter);
var pickedBodies = Submarine.PickBodies(Weapon.SimPosition, Submarine.GetRelativeSimPosition(from: Weapon, to: Enemy),
ignoredBodies: character.AnimController.LimbBodies,
Physics.CollisionCharacter);
foreach (var body in pickedBodies)
{
Character target = body.UserData switch
if (body.UserData is Limb limb)
{
Character c => c,
Limb limb => limb.character,
_ => null
};
if (target != null && target != Enemy && HumanAIController.IsFriendly(target))
{
return;
Character target = limb.character;
if (target != null && target != Enemy && HumanAIController.IsFriendly(target))
{
// Blocked by a friendly target.
isAimBlocked = true;
if (HumanAIController.DebugAI)
{
BlockedPositions.Add(ConvertUnits.ToDisplayUnits(body.Position));
}
// Stand up, so that we might shoot past the friendlies that are crouching.
allowCrouching = false;
standUpTimer = StandUpCooldown;
return;
}
}
}
UseWeapon(deltaTime);
}
}
}
private bool allowCrouching;
private float standUpTimer;
private const float StandUpCooldown = 5;
private void UseWeapon(float deltaTime)
{
// Never allow friendly crew (bots) to attack with deadly weapons.
if (Mode == CombatMode.Arrest && isLethalWeapon && character.IsOnPlayerTeam && Enemy.IsOnPlayerTeam) { return; }
// Enable this to debug intentional friendly fire.
// if (isLethalWeapon && character.TeamID == Enemy.TeamID && character.IsOnPlayerTeam)
// {
// // Never allow friendly crew (bots) to attack with deadly weapons (this check should be redundant)
// Debugger.Break();
// return;
// }
if (allowCrouching && !isMoving && !character.AnimController.InWater && WeaponComponent is not MeleeWeapon)
{
HumanAIController.AnimController.Crouch();
}
character.SetInput(InputType.Shoot, hit: false, held: true);
Weapon.Use(deltaTime, user: character);
SetReloadTime(WeaponComponent);
@@ -1420,11 +1572,8 @@ namespace Barotrauma
break;
}
case MeleeWeapon mw:
{
if (character.AnimController is HumanoidAnimController { Crouching: false })
{
reloadTime = mw.Reload;
}
{
reloadTime = mw.Reload;
break;
}
}
@@ -1485,7 +1634,7 @@ namespace Barotrauma
}
if (ShouldUnequipWeapon)
{
Unequip();
UnequipWeapon();
}
SteeringManager?.Reset();
}
@@ -1495,7 +1644,7 @@ namespace Barotrauma
base.OnAbandon();
if (ShouldUnequipWeapon)
{
Unequip();
UnequipWeapon();
}
SteeringManager?.Reset();
}
@@ -1516,6 +1665,7 @@ namespace Barotrauma
hasAimed = false;
holdFireTimer = 0;
pathBackTimer = 0;
standUpTimer = 0;
isLethalWeapon = false;
canSeeTarget = false;
seekWeaponObjective = null;