diff --git a/Content.Server/Store/StoreRefundComponent.cs b/Content.Server/Store/StoreRefundComponent.cs index 1a6b17c5ea..df35afdf53 100644 --- a/Content.Server/Store/StoreRefundComponent.cs +++ b/Content.Server/Store/StoreRefundComponent.cs @@ -2,12 +2,31 @@ namespace Content.Server.Store.Components; +// TODO: Refund on a per-item/action level. +// Requires a refund button next to each purchase (disabled/invis by default) +// Interactions with ActionUpgrades would need to be modified to reset all upgrade progress and return the original action purchase to the store. + /// /// Keeps track of entities bought from stores for refunds, especially useful if entities get deleted before they can be refunded. /// [RegisterComponent, Access(typeof(StoreSystem))] public sealed partial class StoreRefundComponent : Component { - [ViewVariables, DataField] + /// + /// The store this entity was bought from + /// + [DataField] public EntityUid? StoreEntity; + + /// + /// The time this entity was bought + /// + [DataField] + public TimeSpan? BoughtTime; + + /// + /// How long until this entity disables refund purchase? + /// + [DataField] + public TimeSpan DisableTime = TimeSpan.FromSeconds(300); } diff --git a/Content.Server/Store/Systems/StoreSystem.Refund.cs b/Content.Server/Store/Systems/StoreSystem.Refund.cs index 04bd585ffc..e9d801f9e1 100644 --- a/Content.Server/Store/Systems/StoreSystem.Refund.cs +++ b/Content.Server/Store/Systems/StoreSystem.Refund.cs @@ -1,5 +1,8 @@ using Content.Server.Store.Components; +using Content.Shared.Actions.Events; +using Content.Shared.Interaction.Events; using Content.Shared.Store.Components; +using Content.Shared.Weapons.Ranged.Systems; using Robust.Shared.Containers; namespace Content.Server.Store.Systems; @@ -12,22 +15,39 @@ public sealed partial class StoreSystem SubscribeLocalEvent(OnRefundTerminating); SubscribeLocalEvent(OnEntityRemoved); SubscribeLocalEvent(OnEntityInserted); + SubscribeLocalEvent(OnActionPerformed); + SubscribeLocalEvent(OnUseInHand); + SubscribeLocalEvent(OnShootAttempt); + // TODO: Handle guardian refund disabling when guardians support refunds. } - private void OnEntityRemoved(EntityUid uid, StoreRefundComponent component, EntRemovedFromContainerMessage args) + private void OnEntityRemoved(Entity ent, ref EntRemovedFromContainerMessage args) { - if (component.StoreEntity == null || _actions.TryGetActionData(uid, out _, false) || !TryComp(component.StoreEntity.Value, out var storeComp)) - return; - - DisableRefund(component.StoreEntity.Value, storeComp); + CheckDisableRefund(ent); } - private void OnEntityInserted(EntityUid uid, StoreRefundComponent component, EntInsertedIntoContainerMessage args) + private void OnEntityInserted(Entity ent, ref EntInsertedIntoContainerMessage args) { - if (component.StoreEntity == null || _actions.TryGetActionData(uid, out _) || !TryComp(component.StoreEntity.Value, out var storeComp)) + CheckDisableRefund(ent); + } + + private void OnActionPerformed(Entity ent, ref ActionPerformedEvent args) + { + CheckDisableRefund(ent); + } + + private void OnUseInHand(Entity ent, ref UseInHandEvent args) + { + args.Handled = true; + CheckDisableRefund(ent); + } + + private void OnShootAttempt(Entity ent, ref AttemptShootEvent args) + { + if (args.Cancelled) return; - DisableRefund(component.StoreEntity.Value, storeComp); + CheckDisableRefund(ent); } private void OnStoreTerminating(Entity ent, ref EntityTerminatingEvent args) @@ -52,4 +72,19 @@ public sealed partial class StoreSystem var ev = new RefundEntityDeletedEvent(ent); RaiseLocalEvent(ent.Comp.StoreEntity.Value, ref ev); } + + private void CheckDisableRefund(Entity ent) + { + var component = ent.Comp; + + if (component.StoreEntity == null || !TryComp(component.StoreEntity.Value, out var storeComp) || !storeComp.RefundAllowed) + return; + + var endTime = component.BoughtTime + component.DisableTime; + + if (IsOnStartingMap(component.StoreEntity.Value, storeComp) && _timing.CurTime < endTime) + return; + + DisableRefund(component.StoreEntity.Value, storeComp); + } } diff --git a/Content.Server/Store/Systems/StoreSystem.Ui.cs b/Content.Server/Store/Systems/StoreSystem.Ui.cs index 5af6ce1c97..3f4ccf696d 100644 --- a/Content.Server/Store/Systems/StoreSystem.Ui.cs +++ b/Content.Server/Store/Systems/StoreSystem.Ui.cs @@ -164,7 +164,7 @@ public sealed partial class StoreSystem } if (!IsOnStartingMap(uid, component)) - component.RefundAllowed = false; + DisableRefund(uid, component); //subtract the cash foreach (var (currency, amount) in cost) @@ -332,7 +332,7 @@ public sealed partial class StoreSystem if (!IsOnStartingMap(uid, component)) { - component.RefundAllowed = false; + DisableRefund(uid, component); UpdateUserInterface(buyer, uid, component); } @@ -376,6 +376,7 @@ public sealed partial class StoreSystem component.BoughtEntities.Add(purchase); var refundComp = EnsureComp(purchase); refundComp.StoreEntity = uid; + refundComp.BoughtTime = _timing.CurTime; } private bool IsOnStartingMap(EntityUid store, StoreComponent component) diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs index a57895364d..0625ced087 100644 --- a/Content.Server/Store/Systems/StoreSystem.cs +++ b/Content.Server/Store/Systems/StoreSystem.cs @@ -10,6 +10,7 @@ using JetBrains.Annotations; using Robust.Shared.Prototypes; using Robust.Shared.Utility; using System.Linq; +using Robust.Shared.Timing; using Content.Shared.Mind; namespace Content.Server.Store.Systems; @@ -22,6 +23,7 @@ public sealed partial class StoreSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IGameTiming _timing = default!; public override void Initialize() {