v1.12.6.2 (Spring Update 2026)
This commit is contained in:
@@ -187,6 +187,11 @@ namespace Barotrauma
|
||||
set => Params.Health.DoesBleed = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can this character be contained inside a controller?
|
||||
/// </summary>
|
||||
public bool IsContainable { get; set; }
|
||||
|
||||
public readonly Dictionary<Identifier, SerializableProperty> Properties;
|
||||
public Dictionary<Identifier, SerializableProperty> SerializableProperties
|
||||
{
|
||||
@@ -683,6 +688,11 @@ namespace Barotrauma
|
||||
get { return AnimController.Mass; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The position the character was at when we previously set the transforms of the items in the character's inventory.
|
||||
/// </summary>
|
||||
private Vector2 lastInventoryItemSetTransformPosition;
|
||||
|
||||
public CharacterInventory Inventory { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -788,7 +798,24 @@ namespace Barotrauma
|
||||
set
|
||||
{
|
||||
if (value == selectedCharacter) { return; }
|
||||
if (selectedCharacter != null) { selectedCharacter.selectedBy = null; }
|
||||
//deselect the currently selected character
|
||||
if (selectedCharacter != null)
|
||||
{
|
||||
selectedCharacter.selectedBy = null;
|
||||
//check if some other character has selected the currently selected character too,
|
||||
//and set selectedBy to that other character (otherwise the currently selected character would be unaware they're still being dragged by someone)
|
||||
foreach (var otherCharacter in CharacterList)
|
||||
{
|
||||
if (otherCharacter != this && otherCharacter.selectedCharacter == selectedCharacter)
|
||||
{
|
||||
selectedCharacter.selectedBy = otherCharacter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CharacterHUD.RecreateHudTextsIfControlling(this);
|
||||
|
||||
selectedCharacter = value;
|
||||
if (selectedCharacter != null) { selectedCharacter.selectedBy = this; }
|
||||
#if CLIENT
|
||||
@@ -1642,8 +1669,10 @@ namespace Barotrauma
|
||||
AnimController.FindHull(setInWater: true);
|
||||
if (AnimController.CurrentHull != null) { Submarine = AnimController.CurrentHull.Submarine; }
|
||||
|
||||
IsContainable = prefab.ConfigElement.GetAttributeBool(nameof(IsContainable), def: Mass <= 30.0f);
|
||||
|
||||
CharacterList.Add(this);
|
||||
|
||||
|
||||
Enabled = GameMain.NetworkMember == null;
|
||||
|
||||
if (info != null)
|
||||
@@ -2268,6 +2297,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// Try to detach from the controller if we are currently attached to something that is dangerous for our character
|
||||
if (aiControlled && Stun <= 0f && !IsKnockedDownOrRagdolled && !LockHands && ShouldAvoidStayingAttachedToController())
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember != null)
|
||||
{
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
@@ -2316,7 +2351,7 @@ namespace Barotrauma
|
||||
{
|
||||
attackCoolDown -= deltaTime;
|
||||
}
|
||||
else if (IsKeyDown(InputType.Attack))
|
||||
else if (IsKeyDown(InputType.Attack) && !IsAttachedToController())
|
||||
{
|
||||
//normally the attack target, where to aim the attack and such is handled by EnemyAIController,
|
||||
//but in the case of player-controlled monsters, we handle it here
|
||||
@@ -2843,14 +2878,14 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
if (Screen.Selected == GameMain.SubEditorScreen) { hidden = false; }
|
||||
#endif
|
||||
if (!CanInteract || hidden || !item.IsInteractable(this)) { return false; }
|
||||
|
||||
Controller controller = item.GetComponent<Controller>();
|
||||
if (controller != null && IsAnySelectedItem(item) && controller.IsAttachedUser(this))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!CanInteract || hidden || !item.IsInteractable(this)) { return false; }
|
||||
|
||||
if (item.ParentInventory != null)
|
||||
{
|
||||
return CanAccessInventory(item.ParentInventory);
|
||||
@@ -2972,7 +3007,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.SubEditorScreen && !insideTrigger)
|
||||
//note that the distance to item should be set to 0 above if the character is within the item's bounding box
|
||||
bool closeEnoughToIgnoreVisibilityCheck = distanceToItem <= 0.1f;
|
||||
if (!item.Prefab.InteractThroughWalls && Screen.Selected != GameMain.SubEditorScreen && !insideTrigger && !closeEnoughToIgnoreVisibilityCheck)
|
||||
{
|
||||
var body = Submarine.CheckVisibility(SimPosition, itemPosition, ignoreLevel: true);
|
||||
bool itemCenterVisible = CheckBody(body, item);
|
||||
@@ -3001,7 +3038,6 @@ namespace Barotrauma
|
||||
{
|
||||
return itemCenterVisible;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -3091,7 +3127,11 @@ namespace Barotrauma
|
||||
|
||||
if (!CanInteract)
|
||||
{
|
||||
SelectedItem = SelectedSecondaryItem = null;
|
||||
if (!IsAttachedToController())
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
SelectedSecondaryItem = null;
|
||||
focusedItem = null;
|
||||
if (!AllowInput)
|
||||
{
|
||||
@@ -3110,8 +3150,16 @@ namespace Barotrauma
|
||||
{
|
||||
if (!PlayerInput.PrimaryMouseButtonHeld() || Barotrauma.Inventory.DraggingItemToWorld)
|
||||
{
|
||||
FocusedCharacter = CanInteract || CanEat ? FindCharacterAtPosition(mouseSimPos) : null;
|
||||
if (FocusedCharacter != null && !CanSeeTarget(FocusedCharacter)) { FocusedCharacter = null; }
|
||||
//don't allow focusing on anyone when the health window is open (avoids accidentally selecting someone when closing the window)
|
||||
if (CharacterHealth.OpenHealthWindow != null)
|
||||
{
|
||||
FocusedCharacter = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
FocusedCharacter = CanInteract || CanEat ? FindCharacterAtPosition(mouseSimPos) : null;
|
||||
if (FocusedCharacter != null && !CanSeeTarget(FocusedCharacter)) { FocusedCharacter = null; }
|
||||
}
|
||||
float aimAssist = GameSettings.CurrentConfig.AimAssistAmount * (AnimController.InWater ? 1.5f : 1.0f);
|
||||
if (HeldItems.Any(it => it?.GetComponent<Wire>()?.IsActive ?? false))
|
||||
{
|
||||
@@ -3435,7 +3483,7 @@ namespace Barotrauma
|
||||
|
||||
obstructVisionAmount = Math.Max(obstructVisionAmount - deltaTime, 0.0f);
|
||||
|
||||
if (Inventory != null)
|
||||
if (Inventory != null && Vector2.DistanceSquared(lastInventoryItemSetTransformPosition, Position) > 0.1f)
|
||||
{
|
||||
//do not check for duplicates: this is code is called very frequently, and duplicates don't matter here,
|
||||
//so it's better just to avoid the relatively expensive duplicate check
|
||||
@@ -3444,6 +3492,7 @@ namespace Barotrauma
|
||||
if (item.body == null || item.body.Enabled) { continue; }
|
||||
item.SetTransform(SimPosition, 0.0f, forceSubmarine: Submarine);
|
||||
}
|
||||
lastInventoryItemSetTransformPosition = Position;
|
||||
}
|
||||
|
||||
HideFace = false;
|
||||
@@ -3570,7 +3619,7 @@ namespace Barotrauma
|
||||
{
|
||||
wasRagdolled = IsRagdolled;
|
||||
IsRagdolled = IsKeyDown(InputType.Ragdoll);
|
||||
if (IsRagdolled && IsBot && GameMain.NetworkMember is not { IsClient: true })
|
||||
if (IsRagdolled && !IsPlayer && GameMain.NetworkMember is not { IsClient: true })
|
||||
{
|
||||
ClearInput(InputType.Ragdoll);
|
||||
}
|
||||
@@ -3622,7 +3671,19 @@ namespace Barotrauma
|
||||
AnimController.IgnorePlatforms = true;
|
||||
}
|
||||
AnimController.ResetPullJoints();
|
||||
SelectedItem = SelectedSecondaryItem = null;
|
||||
|
||||
// Prevent us from detaching from the controller if we are attached to it OR detach if we
|
||||
// manually ragdoll, in this case it should be similar to us deselecting the controller
|
||||
if (!IsAttachedToController() ||
|
||||
(IsKeyDown(InputType.Ragdoll)
|
||||
// Let only the server do this check since the Ragdoll input for other clients is set to be held
|
||||
// for stunned characters even if a character isn't manually ragdolling
|
||||
&& (GameMain.NetworkMember == null || GameMain.NetworkMember is { IsServer: true } )))
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
SelectedSecondaryItem = null;
|
||||
SelectedCharacter = null;
|
||||
return;
|
||||
}
|
||||
@@ -3651,6 +3712,13 @@ namespace Barotrauma
|
||||
bool MustDeselect(Item item)
|
||||
{
|
||||
if (item == null) { return false; }
|
||||
|
||||
// Prevent creatures from deselecting the controller if they are attached to it
|
||||
if (IsAIControlled && !CanInteract && IsAttachedToController())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CanInteractWith(item)) { return true; }
|
||||
bool hasSelectableComponent = false;
|
||||
foreach (var component in item.Components)
|
||||
@@ -4376,6 +4444,41 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceSay(LocalizedString messageToSay, bool sayInRadio, bool removeQuotes = false, float delay = 0.0f)
|
||||
{
|
||||
if (messageToSay.IsNullOrEmpty() || SpeechImpediment >= 100.0f || IsDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (removeQuotes)
|
||||
{
|
||||
messageToSay = new TrimLString(messageToSay,
|
||||
TrimLString.Mode.Both, ['"', '”', '“', ' ']);
|
||||
}
|
||||
|
||||
ChatMessageType messageType = ChatMessageType.Default;
|
||||
bool canUseRadio = ChatMessage.CanUseRadio(this, out WifiComponent radio);
|
||||
if (canUseRadio && sayInRadio)
|
||||
{
|
||||
messageType = ChatMessageType.Radio;
|
||||
}
|
||||
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
#if SERVER
|
||||
GameMain.Server?.SendChatMessage(messageToSay.Value, messageType, senderClient: null, this);
|
||||
#elif CLIENT
|
||||
// no need to create the message when playing as a client, the server will send it to us
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
AIChatMessage message = new AIChatMessage(messageToSay.Value, messageType);
|
||||
SendSinglePlayerMessage(message, canUseRadio, radio);
|
||||
}
|
||||
#endif
|
||||
}, delay);
|
||||
}
|
||||
|
||||
public void SetAllDamage(float damageAmount, float bleedingDamageAmount, float burnDamageAmount)
|
||||
{
|
||||
CharacterHealth.SetAllDamage(damageAmount, bleedingDamageAmount, burnDamageAmount);
|
||||
@@ -4760,6 +4863,10 @@ namespace Barotrauma
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient && !isNetworkMessage) { return; }
|
||||
if (Screen.Selected != GameMain.GameScreen) { return; }
|
||||
//don't allow stunning for less than one frame
|
||||
//fixes monsters/enemies that take some minuscule amount of stun from a weapon still being noticeable affected by the stun,
|
||||
//because even a one-frame stun briefly disables the animations and makes the character stop
|
||||
if (newStun < Timing.Step && Stun <= 0.0f) { return; }
|
||||
if (GodMode)
|
||||
{
|
||||
CharacterHealth.Stun = 0;
|
||||
@@ -4787,7 +4894,12 @@ namespace Barotrauma
|
||||
CharacterHealth.Stun = newStun;
|
||||
if (newStun > 0.0f)
|
||||
{
|
||||
SelectedItem = SelectedSecondaryItem = null;
|
||||
if (!IsAttachedToController())
|
||||
{
|
||||
SelectedItem = null;
|
||||
}
|
||||
|
||||
SelectedSecondaryItem = null;
|
||||
if (SelectedCharacter != null) { DeselectCharacter(); }
|
||||
}
|
||||
HealthUpdateInterval = 0.0f;
|
||||
@@ -4976,6 +5088,37 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAttachedToController()
|
||||
{
|
||||
if (SelectedItem == null) { return false; }
|
||||
|
||||
var controller = SelectedItem.GetComponent<Controller>();
|
||||
if (controller == null) { return false; }
|
||||
|
||||
return controller.IsAttachedUser(this);
|
||||
}
|
||||
|
||||
public bool ShouldAvoidStayingAttachedToController()
|
||||
{
|
||||
if (!IsAttachedToController()) { return false; }
|
||||
|
||||
var deconstructor = SelectedItem.GetComponent<Deconstructor>();
|
||||
if (deconstructor != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Character is being carried by an enemy!
|
||||
if (IsHuman &&
|
||||
SelectedItem.GetRootInventoryOwner() is Character carryingCharacter &&
|
||||
TeamID != carryingCharacter.TeamID)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Kill(CauseOfDeathType causeOfDeath, Affliction causeOfDeathAffliction, bool isNetworkMessage = false, bool log = true)
|
||||
{
|
||||
if (IsDead || CharacterHealth.Unkillable || GodMode || Removed) { return; }
|
||||
@@ -5113,7 +5256,7 @@ namespace Barotrauma
|
||||
AnimController.movement = Vector2.Zero;
|
||||
AnimController.TargetMovement = Vector2.Zero;
|
||||
|
||||
if (!LockHands)
|
||||
if (!LockHands && causeOfDeath != CauseOfDeathType.Disconnected)
|
||||
{
|
||||
foreach (Item heldItem in HeldItems.ToList())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user