diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs
index 7bbe23c825..5b062c43f5 100644
--- a/Content.Client/Entry/IgnoredComponents.cs
+++ b/Content.Client/Entry/IgnoredComponents.cs
@@ -293,7 +293,6 @@ namespace Content.Client.Entry
"IncreaseDamageOnWield",
"TabletopGame",
"LitOnPowered",
- "Foldable",
"TriggerOnSignalReceived",
"ToggleDoorOnTrigger",
"DeviceNetworkComponent",
diff --git a/Content.Client/Foldable/FoldableSystem.cs b/Content.Client/Foldable/FoldableSystem.cs
new file mode 100644
index 0000000000..4071f7cd3d
--- /dev/null
+++ b/Content.Client/Foldable/FoldableSystem.cs
@@ -0,0 +1,10 @@
+using Content.Shared.Foldable;
+using JetBrains.Annotations;
+
+namespace Content.Client.Foldable;
+
+[UsedImplicitly]
+public sealed class FoldableSystem : SharedFoldableSystem
+{
+ // classic.
+}
diff --git a/Content.Server/Foldable/FoldableComponent.cs b/Content.Server/Foldable/FoldableComponent.cs
deleted file mode 100644
index 514d4eddb5..0000000000
--- a/Content.Server/Foldable/FoldableComponent.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-#nullable enable
-
-using Robust.Shared.Containers;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Serialization.Manager.Attributes;
-using Robust.Shared.ViewVariables;
-
-namespace Content.Server.Foldable
-{
-
- ///
- /// Used to create "foldable structures" that you can pickup like an item when folded. Used for rollerbeds and wheelchairs
- ///
- [RegisterComponent]
- public class FoldableComponent : Component
- {
- public override string Name => "Foldable";
-
- [DataField("folded")]
- [ViewVariables]
- public bool IsFolded = false;
-
- public bool CanBeFolded = true;
- }
-}
diff --git a/Content.Server/Foldable/FoldableSystem.cs b/Content.Server/Foldable/FoldableSystem.cs
index 380b9f29b5..f6c96a191f 100644
--- a/Content.Server/Foldable/FoldableSystem.cs
+++ b/Content.Server/Foldable/FoldableSystem.cs
@@ -1,8 +1,7 @@
using System.Linq;
using Content.Server.Buckle.Components;
using Content.Server.Storage.Components;
-using Content.Shared.Interaction;
-using Content.Shared.Item;
+using Content.Shared.Foldable;
using Content.Shared.Verbs;
using JetBrains.Annotations;
using Robust.Shared.Containers;
@@ -13,19 +12,15 @@ using Robust.Shared.Localization;
namespace Content.Server.Foldable
{
[UsedImplicitly]
- public sealed class FoldableSystem : EntitySystem
+ public sealed class FoldableSystem : SharedFoldableSystem
{
[Dependency] private SharedContainerSystem _container = default!;
- private const string FoldKey = "FoldedState";
-
public override void Initialize()
{
base.Initialize();
- SubscribeLocalEvent(OnFoldableInit);
SubscribeLocalEvent(OnFoldableOpenAttempt);
- SubscribeLocalEvent(OnPickedUpAttempt);
SubscribeLocalEvent(AddFoldVerb);
}
@@ -35,38 +30,43 @@ namespace Content.Server.Foldable
args.Cancel();
}
- private void OnFoldableInit(EntityUid uid, FoldableComponent component, ComponentInit args)
- {
- SetFolded(component, component.IsFolded);
- }
-
- private bool TryToggleFold(FoldableComponent comp)
+ public bool TryToggleFold(FoldableComponent comp)
{
return TrySetFolded(comp, !comp.IsFolded);
}
+ public bool CanToggleFold(EntityUid uid, FoldableComponent? fold = null)
+ {
+ if (!Resolve(uid, ref fold))
+ return false;
+
+ // Can't un-fold in hands / inventory
+ if (_container.IsEntityInContainer(uid))
+ return false;
+
+ // If an entity is buckled to the object we can't pick it up or fold it
+ if (TryComp(uid, out StrapComponent? strap) && strap.BuckledEntities.Any())
+ return false;
+
+ // Also check if this entity is "open" (e.g., body bags)
+ return !TryComp(uid, out EntityStorageComponent? storage) || !storage.Open;
+
+ }
+
///
/// Try to fold/unfold
///
///
/// Folded state we want
/// True if successful
- private bool TrySetFolded(FoldableComponent comp, bool state)
+ public bool TrySetFolded(FoldableComponent comp, bool state)
{
if (state == comp.IsFolded)
return false;
- if (_container.IsEntityInContainer(comp.Owner))
+ if (!CanToggleFold(comp.Owner, comp))
return false;
- // First we check if the foldable object has a strap component
- if (EntityManager.TryGetComponent(comp.Owner, out StrapComponent? strap))
- {
- // If an entity is buckled to the object we can't pick it up or fold it
- if (strap.BuckledEntities.Any())
- return false;
- }
-
SetFolded(comp, state);
return true;
}
@@ -76,41 +76,20 @@ namespace Content.Server.Foldable
///
///
/// If true, the component will become folded, else unfolded
- private void SetFolded(FoldableComponent component, bool folded)
+ public override void SetFolded(FoldableComponent component, bool folded)
{
- component.IsFolded = folded;
- component.CanBeFolded = !_container.IsEntityInContainer(component.Owner);
+ base.SetFolded(component, folded);
// You can't buckle an entity to a folded object
- if (EntityManager.TryGetComponent(component.Owner, out StrapComponent? strap))
+ if (TryComp(component.Owner, out StrapComponent? strap))
strap.Enabled = !component.IsFolded;
-
- // Update visuals only if the value has changed
- if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearance))
- appearance.SetData(FoldKey, folded);
}
- #region Event handlers
-
- ///
- /// Prevents foldable objects to be picked up when unfolded
- ///
- ///
- ///
- ///
- private void OnPickedUpAttempt(EntityUid uid, FoldableComponent component, AttemptItemPickupEvent args)
- {
- if (!component.IsFolded)
- args.Cancel();
- }
-
- #endregion
-
#region Verb
private void AddFoldVerb(EntityUid uid, FoldableComponent component, GetAlternativeVerbsEvent args)
{
- if (!args.CanAccess || !args.CanInteract)
+ if (!args.CanAccess || !args.CanInteract || !CanToggleFold(uid, component))
return;
Verb verb = new()
diff --git a/Content.Shared/Foldable/FoldableComponent.cs b/Content.Shared/Foldable/FoldableComponent.cs
new file mode 100644
index 0000000000..3d861d42b0
--- /dev/null
+++ b/Content.Shared/Foldable/FoldableComponent.cs
@@ -0,0 +1,35 @@
+using Robust.Shared.Analyzers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.ViewVariables;
+using System;
+
+namespace Content.Shared.Foldable;
+
+///
+/// Used to create "foldable structures" that you can pickup like an item when folded. Used for rollerbeds and wheelchairs
+///
+[RegisterComponent]
+[NetworkedComponent]
+[Friend(typeof(SharedFoldableSystem))]
+public class FoldableComponent : Component
+{
+ public override string Name => "Foldable";
+
+ [DataField("folded")]
+ public bool IsFolded = false;
+}
+
+// ahhh, the ol' "state thats just a copy of the component".
+[Serializable, NetSerializable]
+public class FoldableComponentState : ComponentState
+{
+ public readonly bool IsFolded;
+
+ public FoldableComponentState(bool isFolded)
+ {
+ IsFolded = isFolded;
+ }
+}
diff --git a/Content.Shared/Foldable/SharedFoldableSystem.cs b/Content.Shared/Foldable/SharedFoldableSystem.cs
new file mode 100644
index 0000000000..de5a9e75ba
--- /dev/null
+++ b/Content.Shared/Foldable/SharedFoldableSystem.cs
@@ -0,0 +1,62 @@
+using Content.Shared.Item;
+using JetBrains.Annotations;
+using Robust.Shared.GameObjects;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Foldable;
+
+[UsedImplicitly]
+public abstract class SharedFoldableSystem : EntitySystem
+{
+ private const string FoldKey = "FoldedState";
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnGetState);
+ SubscribeLocalEvent(OnHandleState);
+
+ SubscribeLocalEvent(OnFoldableInit);
+ SubscribeLocalEvent(OnPickedUpAttempt);
+ }
+
+ private void OnGetState(EntityUid uid, FoldableComponent component, ref ComponentGetState args)
+ {
+ args.State = new FoldableComponentState(component.IsFolded);
+ }
+
+ private void OnHandleState(EntityUid uid, FoldableComponent component, ref ComponentHandleState args)
+ {
+ if (args.Current is not FoldableComponentState state)
+ return;
+
+ if (state.IsFolded != component.IsFolded)
+ SetFolded(component, state.IsFolded);
+ }
+
+ private void OnFoldableInit(EntityUid uid, FoldableComponent component, ComponentInit args)
+ {
+ SetFolded(component, component.IsFolded);
+ }
+
+ ///
+ /// Set the folded state of the given
+ ///
+ ///
+ /// If true, the component will become folded, else unfolded
+ public virtual void SetFolded(FoldableComponent component, bool folded)
+ {
+ component.IsFolded = folded;
+ component.Dirty();
+
+ if (TryComp(component.Owner, out AppearanceComponent? appearance))
+ appearance.SetData(FoldKey, folded);
+ }
+
+ private void OnPickedUpAttempt(EntityUid uid, FoldableComponent component, AttemptItemPickupEvent args)
+ {
+ if (!component.IsFolded)
+ args.Cancel();
+ }
+}
diff --git a/Content.Shared/Hands/Components/SharedHandsComponent.cs b/Content.Shared/Hands/Components/SharedHandsComponent.cs
index 3c0e9b131d..3035bfccc7 100644
--- a/Content.Shared/Hands/Components/SharedHandsComponent.cs
+++ b/Content.Shared/Hands/Components/SharedHandsComponent.cs
@@ -14,6 +14,7 @@ using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
+using Robust.Shared.Physics;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
@@ -497,11 +498,14 @@ namespace Content.Shared.Hands.Components
///
protected bool CanInsertEntityIntoHand(Hand hand, EntityUid entity)
{
+ var handContainer = hand.Container;
+ if (handContainer == null) return false;
+
if (!_entMan.HasComponent(entity))
return false;
- var handContainer = hand.Container;
- if (handContainer == null) return false;
+ if (_entMan.TryGetComponent(entity, out IPhysBody? physics) && physics.BodyType == BodyType.Static)
+ return false;
if (!handContainer.CanInsert(entity)) return false;
diff --git a/Content.Shared/Hands/SharedHandsSystem.cs b/Content.Shared/Hands/SharedHandsSystem.cs
index e1c7831a2a..67bf3bfc91 100644
--- a/Content.Shared/Hands/SharedHandsSystem.cs
+++ b/Content.Shared/Hands/SharedHandsSystem.cs
@@ -81,9 +81,6 @@ namespace Content.Shared.Hands
return;
}
- if (TryComp(entity, out SharedSpriteComponent? component))
- component.Visible = true;
-
hands.Dirty();
var unequippedHandMessage = new UnequippedHandEvent(uid, entity, hand);
@@ -115,9 +112,6 @@ namespace Content.Shared.Hands
_adminLogSystem.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(uid):user} picked up {ToPrettyString(entity):entity}");
- if (TryComp(entity, out SharedSpriteComponent? component))
- component.Visible = false;
-
hands.Dirty();
var equippedHandMessage = new EquippedHandEvent(uid, entity, hand);
diff --git a/Content.Shared/Item/ItemSystem.cs b/Content.Shared/Item/ItemSystem.cs
index a712a62a60..1f05a229b0 100644
--- a/Content.Shared/Item/ItemSystem.cs
+++ b/Content.Shared/Item/ItemSystem.cs
@@ -53,11 +53,11 @@ namespace Content.Shared.Item
args.Using != null ||
!args.CanAccess ||
!args.CanInteract ||
- !component.CanPickup(args.User, popup: false))
+ !args.Hands.CanPickupEntityToActiveHand(args.Target))
return;
Verb verb = new();
- verb.Act = () => args.Hands.PutInHand(args.Target);
+ verb.Act = () => args.Hands.TryPickupEntityToActiveHand(args.Target);
verb.IconTexture = "/Textures/Interface/VerbIcons/pickup.svg.192dpi.png";
// if the item already in a container (that is not the same as the user's), then change the text.
diff --git a/Content.Shared/Item/SharedItemComponent.cs b/Content.Shared/Item/SharedItemComponent.cs
index 6b330f932b..34e454b13e 100644
--- a/Content.Shared/Item/SharedItemComponent.cs
+++ b/Content.Shared/Item/SharedItemComponent.cs
@@ -1,5 +1,4 @@
using System;
-using Content.Shared.ActionBlocker;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction;
@@ -11,7 +10,6 @@ using Robust.Shared.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
-using Robust.Shared.Physics;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
@@ -101,28 +99,11 @@ namespace Content.Shared.Item
[DataField("sprite")]
private string? _rsiPath;
- ///
- /// If a player can pick up this item.
- ///
- public bool CanPickup(EntityUid user, bool popup = true)
- {
- if (!EntitySystem.Get().CanPickup(user))
- return false;
-
- if (_entMan.GetComponent(user).MapID != _entMan.GetComponent(Owner).MapID)
- return false;
-
- if (!_entMan.TryGetComponent(Owner, out IPhysBody? physics) || physics.BodyType == BodyType.Static)
- return false;
-
- return user.InRangeUnobstructed(Owner, ignoreInsideBlocker: true, popup: popup);
- }
-
bool IInteractHand.InteractHand(InteractHandEventArgs eventArgs)
{
var user = eventArgs.User;
- if (!CanPickup(user))
+ if (!user.InRangeUnobstructed(Owner, ignoreInsideBlocker: true))
return false;
if (!_entMan.TryGetComponent(user, out SharedHandsComponent hands))
@@ -133,8 +114,8 @@ namespace Content.Shared.Item
if (activeHand == null)
return false;
- hands.TryPickupEntityToActiveHand(Owner, animateUser: true);
- return true;
+ // hands checks action blockers
+ return hands.TryPickupEntityToActiveHand(Owner, animateUser: true);
}
private void OnEquippedPrefixChange()