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
@@ -183,6 +183,13 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize(false, IsPropertySaveable.No, description: "Does the Controller require power to function (= to send signals and move the camera focus to a connected item)?")]
public bool RequirePower
{
get;
set;
}
[Serialize(false, IsPropertySaveable.No, description: "If true, other items can be used simultaneously.")]
public bool IsSecondaryItem
{
@@ -190,6 +197,13 @@ namespace Barotrauma.Items.Components
private set;
}
[Serialize(false, IsPropertySaveable.No, description: "If enabled, the user sticks to the position of this item even if the item moves.")]
public bool ForceUserToStayAttached
{
get;
set;
}
public Controller(Item item, ContentXElement element)
: base(item, element)
{
@@ -199,25 +213,44 @@ namespace Barotrauma.Items.Components
IsActive = true;
}
/// <summary>
/// Hack for allowing characters to interact with a loader to get inside a boarding pod.
/// Doing that simply by autointeracting with the contained pod is difficult, because interacting with the loader selects it
/// _after_ the Select method of the pod is called by the autointeract logic, and the character only goes inside the pod if it's the selected item.
/// </summary>
private bool forceSelectNextFrame;
private float userCanInteractCheckTimer;
private const float UserCanInteractCheckInterval = 1.0f;
public override void Update(float deltaTime, Camera cam)
{
this.cam = cam;
UserInCorrectPosition = false;
if (!ForceUserToStayAttached) { UserInCorrectPosition = false; }
string signal = IsToggle && State ? output : falseOutput;
if (item.Connections != null && IsToggle && !string.IsNullOrEmpty(signal))
if (item.Connections != null && IsToggle && !string.IsNullOrEmpty(signal) && !IsOutOfPower())
{
item.SendSignal(signal, "signal_out");
item.SendSignal(signal, "trigger_out");
}
if (forceSelectNextFrame && user != null)
{
user.SelectedItem = item;
}
forceSelectNextFrame = false;
userCanInteractCheckTimer -= deltaTime;
if (user == null
|| user.Removed
|| !user.IsAnySelectedItem(item)
|| item.ParentInventory != null
|| !user.CanInteractWith(item)
|| (item.ParentInventory != null && !IsAttachedUser(user))
|| (UsableIn == UseEnvironment.Water && !user.AnimController.InWater)
|| (UsableIn == UseEnvironment.Air && user.AnimController.InWater))
|| (UsableIn == UseEnvironment.Air && user.AnimController.InWater)
|| !CheckUserCanInteract())
{
if (user != null)
{
@@ -228,6 +261,17 @@ namespace Barotrauma.Items.Components
return;
}
if (ForceUserToStayAttached && Vector2.DistanceSquared(item.WorldPosition, user.WorldPosition) > 0.1f)
{
user.TeleportTo(item.WorldPosition);
user.AnimController.Collider.ResetDynamics();
foreach (var limb in user.AnimController.Limbs)
{
if (limb.Removed || limb.IsSevered) { continue; }
limb.body?.ResetDynamics();
}
}
user.AnimController.StartUsingItem();
if (userPos != Vector2.Zero)
@@ -330,6 +374,22 @@ namespace Barotrauma.Items.Components
}
}
private bool CheckUserCanInteract()
{
//optimization: CanInteractWith is relatively heavy (can involve visibility checks for example), let's not do it every frame
if (user != null)
{
if (userCanInteractCheckTimer <= 0.0f)
{
userCanInteractCheckTimer = UserCanInteractCheckInterval;
return user.CanInteractWith(item);
}
}
//we only do the actual check every UserCanInteractCheckInterval seconds
//can mean the component can stay selected for <1s after the user no longer has access to it
return true;
}
private double lastUsed;
public override bool Use(float deltaTime, Character activator = null)
@@ -344,6 +404,8 @@ namespace Barotrauma.Items.Components
return false;
}
if (IsOutOfPower()) { return false; }
if (IsToggle && (activator == null || lastUsed < Timing.TotalTime - 0.1))
{
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
@@ -380,6 +442,8 @@ namespace Barotrauma.Items.Components
return false;
}
if (IsOutOfPower()) { return false; }
focusTarget = GetFocusTarget();
if (focusTarget == null)
@@ -417,11 +481,20 @@ namespace Barotrauma.Items.Components
return true;
}
public bool IsOutOfPower()
{
if (!RequirePower) { return false; }
var powered = item.GetComponent<Powered>();
return powered == null || powered.Voltage < powered.MinVoltage;
}
public Item GetFocusTarget()
{
var positionOut = item.Connections?.Find(c => c.Name == "position_out");
if (positionOut == null) { return null; }
if (IsOutOfPower()) { return null; }
item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), positionOut);
for (int i = item.LastSentSignalRecipients.Count - 1; i >= 0; i--)
@@ -447,6 +520,7 @@ namespace Barotrauma.Items.Components
public override bool Pick(Character picker)
{
if (IsOutOfPower()) { return false; }
#if CLIENT
if (Screen.Selected == GameMain.SubEditorScreen) { return false; }
#endif
@@ -539,7 +613,16 @@ namespace Barotrauma.Items.Components
{
user = activator;
IsActive = true;
if (ForceUserToStayAttached && item.Container != null)
{
forceSelectNextFrame = true;
return false;
}
}
//allow the selection logic above to run when out of power, but allow sending signals
if (IsOutOfPower()) { return false; }
#if SERVER
item.CreateServerEvent(this);
#endif
@@ -550,6 +633,14 @@ namespace Barotrauma.Items.Components
return true;
}
/// <summary>
/// "Attached user" sticks to this item. Can be used for things such as clown crates and boarding pods.
/// </summary>
public bool IsAttachedUser(Character character)
{
return character != null && character == user && ForceUserToStayAttached;
}
public override void FlipX(bool relativeToSub)
{
if (dir != Direction.None)