2024-07-23 12:04:09 +03:00
using Content.Shared.DisplacementMap ;
2023-04-07 11:21:12 -07:00
using Content.Shared.Hands.EntitySystems ;
2021-06-21 02:21:20 -07:00
using Robust.Shared.Containers ;
2021-07-12 01:32:10 -07:00
using Robust.Shared.GameStates ;
2019-11-13 17:37:46 -05:00
using Robust.Shared.Serialization ;
2017-09-26 21:27:48 +02:00
2022-03-17 20:13:31 +13:00
namespace Content.Shared.Hands.Components ;
2021-06-21 02:21:20 -07:00
2024-02-26 04:36:19 +01:00
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
2023-04-07 11:21:12 -07:00
[Access(typeof(SharedHandsSystem))]
2023-08-22 18:14:33 -07:00
public sealed partial class HandsComponent : Component
2022-03-17 20:13:31 +13:00
{
/// <summary>
/// The currently active hand.
/// </summary>
[ViewVariables]
public Hand ? ActiveHand ;
2021-07-31 03:14:00 +02:00
2022-03-17 20:13:31 +13:00
/// <summary>
/// The item currently held in the active hand.
/// </summary>
[ViewVariables]
public EntityUid ? ActiveHandEntity = > ActiveHand ? . HeldEntity ;
2020-07-25 15:11:16 +02:00
2022-03-17 20:13:31 +13:00
[ViewVariables]
public Dictionary < string , Hand > Hands = new ( ) ;
2017-09-26 21:27:48 +02:00
2022-03-17 20:13:31 +13:00
public int Count = > Hands . Count ;
2018-04-22 06:11:38 -05:00
/// <summary>
2022-03-17 20:13:31 +13:00
/// List of hand-names. These are keys for <see cref="Hands"/>. The order of this list determines the order in which hands are iterated over.
2018-04-22 06:11:38 -05:00
/// </summary>
2022-03-17 20:13:31 +13:00
public List < string > SortedHands = new ( ) ;
2018-11-21 20:58:11 +01:00
2024-04-02 07:18:31 +02:00
/// <summary>
/// If true, the items in the hands won't be affected by explosions.
/// </summary>
[DataField]
public bool DisableExplosionRecursion = false ;
2020-01-17 18:41:47 -08:00
/// <summary>
2024-07-08 11:03:53 +02:00
/// Modifies the speed at which items are thrown.
2020-01-17 18:41:47 -08:00
/// </summary>
2024-07-08 11:03:53 +02:00
[DataField]
2022-03-17 20:13:31 +13:00
[ViewVariables(VVAccess.ReadWrite)]
2024-07-12 12:32:47 +02:00
public float BaseThrowspeed { get ; set ; } = 11f ;
2020-01-17 18:41:47 -08:00
2021-06-21 02:21:20 -07:00
/// <summary>
2022-03-17 20:13:31 +13:00
/// Distance after which longer throw targets stop increasing throw impulse.
2021-06-21 02:21:20 -07:00
/// </summary>
2022-03-17 20:13:31 +13:00
[DataField("throwRange")]
[ViewVariables(VVAccess.ReadWrite)]
public float ThrowRange { get ; set ; } = 8f ;
2023-04-07 11:21:12 -07:00
/// <summary>
/// Whether or not to add in-hand sprites for held items. Some entities (e.g., drones) don't want these.
/// Used by the client.
/// </summary>
[DataField("showInHands")]
public bool ShowInHands = true ;
/// <summary>
/// Data about the current sprite layers that the hand is contributing to the owner entity. Used for sprite in-hands.
/// Used by the client.
/// </summary>
public readonly Dictionary < HandLocation , HashSet < string > > RevealedLayers = new ( ) ;
2023-12-31 22:24:37 -05:00
/// <summary>
/// The time at which throws will be allowed again.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
2024-02-26 04:36:19 +01:00
[AutoPausedField]
2023-12-31 22:24:37 -05:00
public TimeSpan NextThrowTime ;
/// <summary>
/// The minimum time inbetween throws.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public TimeSpan ThrowCooldown = TimeSpan . FromSeconds ( 0.5f ) ;
2024-07-23 12:04:09 +03:00
[DataField]
public DisplacementData ? HandDisplacement ;
2024-10-03 02:11:56 +02:00
/// <summary>
/// If false, hands cannot be stripped, and they do not show up in the stripping menu.
/// </summary>
[DataField]
public bool CanBeStripped = true ;
2022-03-17 20:13:31 +13:00
}
2018-11-21 20:58:11 +01:00
2022-03-17 20:13:31 +13:00
[Serializable, NetSerializable]
2022-09-11 21:30:11 -07:00
public sealed class Hand //TODO: This should definitely be a struct - Jezi
2022-03-17 20:13:31 +13:00
{
[ViewVariables]
public string Name { get ; }
[ViewVariables]
public HandLocation Location { get ; }
2019-08-31 17:49:18 -07:00
2021-06-21 02:21:20 -07:00
/// <summary>
2022-03-17 20:13:31 +13:00
/// The container used to hold the contents of this hand. Nullable because the client must get the containers via <see cref="ContainerManagerComponent"/>,
/// which may not be synced with the server when the client hands are created.
2021-06-21 02:21:20 -07:00
/// </summary>
2022-03-17 20:13:31 +13:00
[ViewVariables, NonSerialized]
public ContainerSlot ? Container ;
2019-08-31 17:49:18 -07:00
2022-03-17 20:13:31 +13:00
[ViewVariables]
public EntityUid ? HeldEntity = > Container ? . ContainedEntity ;
2020-10-28 10:16:40 +01:00
2022-03-17 20:13:31 +13:00
public bool IsEmpty = > HeldEntity = = null ;
public Hand ( string name , HandLocation location , ContainerSlot ? container = null )
2020-07-25 15:11:16 +02:00
{
2022-03-17 20:13:31 +13:00
Name = name ;
Location = location ;
Container = container ;
2020-07-25 15:11:16 +02:00
}
2022-03-17 20:13:31 +13:00
}
2021-02-03 22:07:13 +00:00
2022-03-17 20:13:31 +13:00
[Serializable, NetSerializable]
public sealed class HandsComponentState : ComponentState
{
public readonly List < Hand > Hands ;
public readonly List < string > HandNames ;
public readonly string? ActiveHand ;
2021-06-21 02:21:20 -07:00
2023-04-07 11:21:12 -07:00
public HandsComponentState ( HandsComponent handComp )
2022-03-17 20:13:31 +13:00
{
2023-10-22 16:55:10 +11:00
// cloning lists because of test networking.
2022-03-17 20:13:31 +13:00
Hands = new ( handComp . Hands . Values ) ;
2023-10-22 16:55:10 +11:00
HandNames = new ( handComp . SortedHands ) ;
2022-03-17 20:13:31 +13:00
ActiveHand = handComp . ActiveHand ? . Name ;
2021-06-21 02:21:20 -07:00
}
2017-09-26 21:27:48 +02:00
}
2022-03-17 20:13:31 +13:00
/// <summary>
/// What side of the body this hand is on.
/// </summary>
2024-04-24 16:01:31 +02:00
/// <seealso cref="HandUILocation"/>
/// <seealso cref="HandLocationExt"/>
2022-03-17 20:13:31 +13:00
public enum HandLocation : byte
{
Left ,
Middle ,
Right
}
2024-04-24 16:01:31 +02:00
/// <summary>
/// What side of the UI a hand is on.
/// </summary>
/// <seealso cref="HandLocationExt"/>
/// <seealso cref="HandLocation"/>
public enum HandUILocation : byte
{
Left ,
Right
}
/// <summary>
/// Helper functions for working with <see cref="HandLocation"/>.
/// </summary>
public static class HandLocationExt
{
/// <summary>
/// Convert a <see cref="HandLocation"/> into the appropriate <see cref="HandUILocation"/>.
/// This maps "middle" hands to <see cref="HandUILocation.Right"/>.
/// </summary>
public static HandUILocation GetUILocation ( this HandLocation location )
{
return location switch
{
HandLocation . Left = > HandUILocation . Left ,
HandLocation . Middle = > HandUILocation . Right ,
HandLocation . Right = > HandUILocation . Right ,
_ = > throw new ArgumentOutOfRangeException ( nameof ( location ) , location , null )
} ;
}
}