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()