From 7168959929b87dd392c5cbc3d29bdb9bd315c060 Mon Sep 17 00:00:00 2001 From: keronshb <54602815+keronshb@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:27:28 -0400 Subject: [PATCH] Adds real-time charge & disabled action information to Actions (#31821) --- Content.Client/Actions/ActionsSystem.cs | 27 ++++++++ Content.Shared/Actions/BaseActionComponent.cs | 14 ++++ Content.Shared/Actions/SharedActionsSystem.cs | 64 +++++++++++++++++-- 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 26a22fa8b8..7b13233bab 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -51,6 +51,29 @@ namespace Content.Client.Actions SubscribeLocalEvent(OnEntityWorldTargetHandleState); } + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + var worldActionQuery = EntityQueryEnumerator(); + while (worldActionQuery.MoveNext(out var uid, out var action)) + { + UpdateAction(uid, action); + } + + var instantActionQuery = EntityQueryEnumerator(); + while (instantActionQuery.MoveNext(out var uid, out var action)) + { + UpdateAction(uid, action); + } + + var entityActionQuery = EntityQueryEnumerator(); + while (entityActionQuery.MoveNext(out var uid, out var action)) + { + UpdateAction(uid, action); + } + } + private void OnInstantHandleState(EntityUid uid, InstantActionComponent component, ref ComponentHandleState args) { if (args.Current is not InstantActionComponentState state) @@ -95,6 +118,8 @@ namespace Content.Client.Actions component.Icon = state.Icon; component.IconOn = state.IconOn; component.IconColor = state.IconColor; + component.OriginalIconColor = state.OriginalIconColor; + component.DisabledIconColor = state.DisabledIconColor; component.Keywords.Clear(); component.Keywords.UnionWith(state.Keywords); component.Enabled = state.Enabled; @@ -125,6 +150,8 @@ namespace Content.Client.Actions if (!ResolveActionData(actionId, ref action)) return; + action.IconColor = action.Charges < 1 ? action.DisabledIconColor : action.OriginalIconColor; + base.UpdateAction(actionId, action); if (_playerManager.LocalEntity != action.AttachedEntity) return; diff --git a/Content.Shared/Actions/BaseActionComponent.cs b/Content.Shared/Actions/BaseActionComponent.cs index 9156f747f5..01452bdc72 100644 --- a/Content.Shared/Actions/BaseActionComponent.cs +++ b/Content.Shared/Actions/BaseActionComponent.cs @@ -40,6 +40,16 @@ public abstract partial class BaseActionComponent : Component /// [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. /// @@ -179,6 +189,8 @@ 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; @@ -209,6 +221,8 @@ public abstract class BaseActionComponentState : ComponentState Icon = component.Icon; IconOn = component.IconOn; IconColor = component.IconColor; + OriginalIconColor = component.OriginalIconColor; + DisabledIconColor = component.DisabledIconColor; Keywords = component.Keywords; Enabled = component.Enabled; Toggled = component.Toggled; diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 2756345428..76b8a1b081 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -69,8 +69,42 @@ public abstract class SharedActionsSystem : EntitySystem SubscribeAllEvent(OnActionRequest); } + public override void Update(float frameTime) + { + base.Update(frameTime); + + var worldActionQuery = EntityQueryEnumerator(); + while (worldActionQuery.MoveNext(out var uid, out var action)) + { + if (IsCooldownActive(action) || !ShouldResetCharges(action)) + continue; + + ResetCharges(uid, dirty: true); + } + + var instantActionQuery = EntityQueryEnumerator(); + while (instantActionQuery.MoveNext(out var uid, out var action)) + { + if (IsCooldownActive(action) || !ShouldResetCharges(action)) + continue; + + ResetCharges(uid, dirty: true); + } + + var entityActionQuery = EntityQueryEnumerator(); + while (entityActionQuery.MoveNext(out var uid, out var action)) + { + if (IsCooldownActive(action) || !ShouldResetCharges(action)) + continue; + + ResetCharges(uid, dirty: true); + } + } + private void OnActionMapInit(EntityUid uid, BaseActionComponent component, MapInitEvent args) { + component.OriginalIconColor = component.IconColor; + if (component.Charges == null) return; @@ -326,14 +360,18 @@ public abstract class SharedActionsSystem : EntitySystem Dirty(actionId.Value, action); } - public void ResetCharges(EntityUid? actionId) + public void ResetCharges(EntityUid? actionId, bool update = false, bool dirty = false) { if (!TryGetActionData(actionId, out var action)) return; action.Charges = action.MaxCharges; - UpdateAction(actionId, action); - Dirty(actionId.Value, action); + + if (update) + UpdateAction(actionId, action); + + if (dirty) + Dirty(actionId.Value, action); } private void OnActionsGetState(EntityUid uid, ActionsComponent component, ref ComponentGetState args) @@ -386,13 +424,12 @@ public abstract class SharedActionsSystem : EntitySystem return; var curTime = GameTiming.CurTime; - // TODO: Check for charge recovery timer - if (action.Cooldown.HasValue && action.Cooldown.Value.End > curTime) + if (IsCooldownActive(action, curTime)) return; // TODO: Replace with individual charge recovery when we have the visuals to aid it if (action is { Charges: < 1, RenewCharges: true }) - ResetCharges(actionEnt); + ResetCharges(actionEnt, true, true); BaseActionEvent? performEvent = null; @@ -1072,4 +1109,19 @@ public abstract class SharedActionsSystem : EntitySystem action.EntityIcon = icon; Dirty(uid, action); } + + /// + /// Checks if the action has a cooldown and if it's still active + /// + protected bool IsCooldownActive(BaseActionComponent action, TimeSpan? curTime = null) + { + curTime ??= GameTiming.CurTime; + // TODO: Check for charge recovery timer + return action.Cooldown.HasValue && action.Cooldown.Value.End > curTime; + } + + protected bool ShouldResetCharges(BaseActionComponent action) + { + return action is { Charges: < 1, RenewCharges: true }; + } } -- 2.51.2