using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Actions; // TODO ACTIONS make this a separate component and remove the inheritance stuff. // TODO ACTIONS convert to auto comp state? // TODO add access attribute. Need to figure out what to do with decal & mapping actions. // [Access(typeof(SharedActionsSystem))] [EntityCategory("Actions")] public abstract partial class BaseActionComponent : Component { public abstract BaseActionEvent? BaseEvent { get; } /// /// Icon representing this action in the UI. /// [DataField("icon")] public SpriteSpecifier? Icon; /// /// For toggle actions only, icon to show when toggled on. If omitted, the action will simply be highlighted /// when turned on. /// [DataField("iconOn")] public SpriteSpecifier? IconOn; /// /// For toggle actions only, background to show when toggled on. /// [DataField] public SpriteSpecifier? BackgroundOn; /// /// If not null, this color will modulate the action icon color. /// /// /// This currently only exists for decal-placement actions, so that the action icons correspond to the color of /// the decal. But this is probably useful for other actions, including maybe changing color on toggle. /// [DataField("iconColor")] public Color IconColor = Color.White; /// /// The original this action was. /// [DataField] public Color OriginalIconColor; /// /// The color the action should turn to when disabled /// [DataField] public Color DisabledIconColor = Color.DimGray; /// /// Keywords that can be used to search for this action in the action menu. /// [DataField("keywords")] public HashSet Keywords = new(); /// /// Whether this action is currently enabled. If not enabled, this action cannot be performed. /// [DataField("enabled")] public bool Enabled = true; /// /// The toggle state of this action. Toggling switches the currently displayed icon, see and . /// /// /// The toggle can set directly via , but it will also be /// automatically toggled for targeted-actions while selecting a target. /// [DataField] public bool Toggled; /// /// The current cooldown on the action. /// // TODO serialization public (TimeSpan Start, TimeSpan End)? Cooldown; /// /// If true, the action will have an initial cooldown applied upon addition. /// [DataField] public bool StartDelay = false; /// /// Time interval between action uses. /// [DataField("useDelay")] public TimeSpan? UseDelay; /// /// The entity that contains this action. If the action is innate, this may be the user themselves. /// This should almost always be non-null. /// [Access(typeof(ActionContainerSystem), typeof(SharedActionsSystem))] [DataField] public EntityUid? Container; /// /// Entity to use for the action icon. If no entity is provided and the differs from /// , then it will default to using /// public EntityUid? EntityIcon { get { if (EntIcon != null) return EntIcon; if (AttachedEntity != Container) return Container; return null; } set => EntIcon = value; } [DataField] public EntityUid? EntIcon; /// /// Whether the action system should block this action if the user cannot currently interact. Some spells or /// abilities may want to disable this and implement their own checks. /// [DataField("checkCanInteract")] public bool CheckCanInteract = true; /// /// Whether to check if the user is conscious or not. Can be used instead of /// for a more permissive check. /// [DataField] public bool CheckConsciousness = true; /// /// If true, this will cause the action to only execute locally without ever notifying the server. /// [DataField("clientExclusive")] public bool ClientExclusive = false; /// /// Determines the order in which actions are automatically added the action bar. /// [DataField("priority")] public int Priority = 0; /// /// What entity, if any, currently has this action in the actions component? /// [DataField] public EntityUid? AttachedEntity; /// /// If true, this will cause the the action event to always be raised directed at the action performer/user instead of the action's container/provider. /// [DataField] public bool RaiseOnUser; /// /// If true, this will cause the the action event to always be raised directed at the action itself instead of the action's container/provider. /// Takes priority over RaiseOnUser. /// [DataField] [Obsolete("This datafield will be reworked in an upcoming action refactor")] public bool RaiseOnAction; /// /// Whether or not to automatically add this action to the action bar when it becomes available. /// [DataField("autoPopulate")] public bool AutoPopulate = true; /// /// Temporary actions are deleted when they get removed a . /// [DataField("temporary")] public bool Temporary; /// /// Determines the appearance of the entity-icon for actions that are enabled via some entity. /// [DataField("itemIconStyle")] public ItemActionIconStyle ItemIconStyle; /// /// If not null, this sound will be played when performing this action. /// [DataField("sound")] public SoundSpecifier? Sound; } [Serializable, NetSerializable] public abstract class BaseActionComponentState : ComponentState { public SpriteSpecifier? Icon; public SpriteSpecifier? IconOn; public Color IconColor; public Color OriginalIconColor; public Color DisabledIconColor; public HashSet Keywords; public bool Enabled; public bool Toggled; public (TimeSpan Start, TimeSpan End)? Cooldown; public TimeSpan? UseDelay; public NetEntity? Container; public NetEntity? EntityIcon; public bool CheckCanInteract; public bool CheckConsciousness; public bool ClientExclusive; public int Priority; public NetEntity? AttachedEntity; public bool RaiseOnUser; public bool RaiseOnAction; public bool AutoPopulate; public bool Temporary; public ItemActionIconStyle ItemIconStyle; public SoundSpecifier? Sound; protected BaseActionComponentState(BaseActionComponent component, IEntityManager entManager) { Container = entManager.GetNetEntity(component.Container); EntityIcon = entManager.GetNetEntity(component.EntIcon); AttachedEntity = entManager.GetNetEntity(component.AttachedEntity); RaiseOnUser = component.RaiseOnUser; RaiseOnAction = component.RaiseOnAction; Icon = component.Icon; IconOn = component.IconOn; IconColor = component.IconColor; OriginalIconColor = component.OriginalIconColor; DisabledIconColor = component.DisabledIconColor; Keywords = component.Keywords; Enabled = component.Enabled; Toggled = component.Toggled; Cooldown = component.Cooldown; UseDelay = component.UseDelay; CheckCanInteract = component.CheckCanInteract; CheckConsciousness = component.CheckConsciousness; ClientExclusive = component.ClientExclusive; Priority = component.Priority; AutoPopulate = component.AutoPopulate; Temporary = component.Temporary; ItemIconStyle = component.ItemIconStyle; Sound = component.Sound; } }