using Content.Shared.DisplacementMap;
using Content.Shared.Hands.EntitySystems;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Hands.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
[Access(typeof(SharedHandsSystem))]
public sealed partial class HandsComponent : Component
{
///
/// The currently active hand.
///
[DataField]
public string? ActiveHandId;
///
/// Dictionary relating a unique hand ID corresponding to a container slot on the attached entity to a class containing information about the Hand itself.
///
[DataField]
public Dictionary Hands = new();
///
/// The number of hands
///
[ViewVariables]
public int Count => Hands.Count;
///
/// List of hand-names. These are keys for . The order of this list determines the order in which hands are iterated over.
///
[DataField]
public List SortedHands = new();
///
/// If true, the items in the hands won't be affected by explosions.
///
[DataField]
public bool DisableExplosionRecursion;
///
/// Modifies the speed at which items are thrown.
///
[DataField]
public float BaseThrowspeed = 11f;
///
/// Distance after which longer throw targets stop increasing throw impulse.
///
[DataField]
public float ThrowRange = 8f;
///
/// Whether or not to add in-hand sprites for held items. Some entities (e.g., drones) don't want these.
/// Used by the client.
///
[DataField]
public bool ShowInHands = true;
///
/// Data about the current sprite layers that the hand is contributing to the owner entity. Used for sprite in-hands.
/// Used by the client.
///
public readonly Dictionary> RevealedLayers = new();
///
/// The time at which throws will be allowed again.
///
[DataField, AutoPausedField]
public TimeSpan NextThrowTime;
///
/// The minimum time inbetween throws.
///
[DataField]
public TimeSpan ThrowCooldown = TimeSpan.FromSeconds(0.5f);
///
/// Fallback displacement map applied to all sprites in the hand, unless otherwise specified
///
[DataField]
public DisplacementData? HandDisplacement;
///
/// If defined, applies to all sprites in the left hand, ignoring
///
[DataField]
public DisplacementData? LeftHandDisplacement;
///
/// If defined, applies to all sprites in the right hand, ignoring
///
[DataField]
public DisplacementData? RightHandDisplacement;
///
/// If false, hands cannot be stripped, and they do not show up in the stripping menu.
///
[DataField]
public bool CanBeStripped = true;
}
[DataDefinition]
[Serializable, NetSerializable]
public partial record struct Hand
{
[DataField]
public HandLocation Location = HandLocation.Right;
public Hand()
{
}
public Hand(HandLocation location)
{
Location = location;
}
}
[Serializable, NetSerializable]
public sealed class HandsComponentState : ComponentState
{
public readonly Dictionary Hands;
public readonly List SortedHands;
public readonly string? ActiveHandId;
public HandsComponentState(HandsComponent handComp)
{
// cloning lists because of test networking.
Hands = new(handComp.Hands);
SortedHands = new(handComp.SortedHands);
ActiveHandId = handComp.ActiveHandId;
}
}
///
/// What side of the body this hand is on.
///
///
///
public enum HandLocation : byte
{
Left,
Middle,
Right
}
///
/// What side of the UI a hand is on.
///
///
///
public enum HandUILocation : byte
{
Left,
Right
}
///
/// Helper functions for working with .
///
public static class HandLocationExt
{
///
/// Convert a into the appropriate .
/// This maps "middle" hands to .
///
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)
};
}
}