using Content.Shared.Mobs; using Robust.Shared.Audio; using Robust.Shared.Serialization; using Robust.Shared.Utility; namespace Content.Shared.Actions; // TODO ACTIONS make this a seprate 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))] 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; /// /// 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; /// /// 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; /// /// Time interval between action uses. /// [DataField("useDelay")] public TimeSpan? UseDelay; /// /// Convenience tool for actions with limited number of charges. Automatically decremented on use, and the /// action is disabled when it reaches zero. Does NOT automatically remove the action from the action bar. /// However, charges will regenerate if is enabled and the action will not disable /// when charges reach zero. /// [DataField("charges")] public int? Charges; /// /// The max charges this action has. If null, this is set automatically from on mapinit. /// [DataField] public int? MaxCharges; /// /// If enabled, charges will regenerate after a is complete /// [DataField("renewCharges")]public bool RenewCharges; /// /// 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; /// /// 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 HashSet Keywords; public bool Enabled; public bool Toggled; public (TimeSpan Start, TimeSpan End)? Cooldown; public TimeSpan? UseDelay; public int? Charges; public int? MaxCharges; public bool RenewCharges; 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 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; Icon = component.Icon; IconOn = component.IconOn; IconColor = component.IconColor; Keywords = component.Keywords; Enabled = component.Enabled; Toggled = component.Toggled; Cooldown = component.Cooldown; UseDelay = component.UseDelay; Charges = component.Charges; MaxCharges = component.MaxCharges; RenewCharges = component.RenewCharges; CheckCanInteract = component.CheckCanInteract; CheckConsciousness = component.CheckConsciousness; ClientExclusive = component.ClientExclusive; Priority = component.Priority; AutoPopulate = component.AutoPopulate; Temporary = component.Temporary; ItemIconStyle = component.ItemIconStyle; Sound = component.Sound; } }