diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactCrusherSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactCrusherSystem.cs index 885186f79c..05bb2327e6 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactCrusherSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactCrusherSystem.cs @@ -1,87 +1,25 @@ using Content.Server.Body.Systems; -using Content.Server.Popups; -using Content.Server.Power.EntitySystems; using Content.Server.Stack; using Content.Shared.Body.Components; -using Content.Shared.Damage; -using Content.Shared.Power; using Content.Shared.Storage.Components; -using Content.Shared.Verbs; using Content.Shared.Whitelist; using Content.Shared.Xenoarchaeology.Equipment; using Content.Shared.Xenoarchaeology.Equipment.Components; using Robust.Shared.Collections; using Robust.Shared.Random; -using Robust.Shared.Timing; namespace Content.Server.Xenoarchaeology.Equipment.Systems; /// public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem { - [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly BodySystem _body = default!; - [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] private readonly StackSystem _stack = default!; - [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - /// - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent>(OnGetVerbs); - SubscribeLocalEvent(OnPowerChanged); - } - - private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing) - return; - - if (!TryComp(ent, out var entityStorageComp) || - entityStorageComp.Contents.ContainedEntities.Count == 0) - return; - - if (!this.IsPowered(ent, EntityManager)) - return; - - var verb = new AlternativeVerb - { - Text = Loc.GetString("artifact-crusher-verb-start-crushing"), - Priority = 2, - Act = () => StartCrushing((ent, ent.Comp, entityStorageComp)) - }; - args.Verbs.Add(verb); - } - - private void OnPowerChanged(Entity ent, ref PowerChangedEvent args) - { - if (!args.Powered) - StopCrushing(ent); - } - - public void StartCrushing(Entity ent) - { - var (uid, crusher, _) = ent; - - if (crusher.Crushing) - return; - - if (crusher.AutoLock) - _popup.PopupEntity(Loc.GetString("artifact-crusher-autolocks-enable"), uid); - - crusher.Crushing = true; - crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1); - crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration; - crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent); - Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true); - Dirty(ent, ent.Comp1); - } - - public void FinishCrushing(Entity ent) + // TODO: Move to shared once StackSystem spawning is in Shared and we have RandomPredicted + public override void FinishCrushing(Entity ent) { var (_, crusher, storage) = ent; StopCrushing((ent, ent.Comp1), false); @@ -113,32 +51,4 @@ public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem } } } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var crusher, out var storage)) - { - if (!crusher.Crushing) - continue; - - if (crusher.NextSecond < _timing.CurTime) - { - var contents = new ValueList(storage.Contents.ContainedEntities); - foreach (var contained in contents) - { - _damageable.TryChangeDamage(contained, crusher.CrushingDamage); - } - crusher.NextSecond += TimeSpan.FromSeconds(1); - Dirty(uid, crusher); - } - - if (crusher.CrushEndTime < _timing.CurTime) - { - FinishCrushing((uid, crusher, storage)); - } - } - } } diff --git a/Content.Shared/Xenoarchaeology/Equipment/Components/ArtifactCrusherComponent.cs b/Content.Shared/Xenoarchaeology/Equipment/Components/ArtifactCrusherComponent.cs index 69a682b660..1130d9f305 100644 --- a/Content.Shared/Xenoarchaeology/Equipment/Components/ArtifactCrusherComponent.cs +++ b/Content.Shared/Xenoarchaeology/Equipment/Components/ArtifactCrusherComponent.cs @@ -2,7 +2,6 @@ using Content.Shared.Damage; using Content.Shared.Stacks; using Content.Shared.Whitelist; using Robust.Shared.Audio; -using Robust.Shared.Audio.Components; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -14,7 +13,8 @@ namespace Content.Shared.Xenoarchaeology.Equipment.Components; /// /// This is an entity storage that, when activated, crushes the artifact inside of it and gives artifact fragments. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] [Access(typeof(SharedArtifactCrusherSystem))] public sealed partial class ArtifactCrusherComponent : Component { @@ -27,19 +27,21 @@ public sealed partial class ArtifactCrusherComponent : Component /// /// When the current crushing will end. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] public TimeSpan CrushEndTime; /// /// The next second. Used to apply damage over time. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] public TimeSpan NextSecond; /// /// The total duration of the crushing. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public TimeSpan CrushDuration = TimeSpan.FromSeconds(10); /// @@ -51,19 +53,19 @@ public sealed partial class ArtifactCrusherComponent : Component /// /// The minimum amount of fragments spawned. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public int MinFragments = 2; /// /// The maximum amount of fragments spawned, non-inclusive. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public int MaxFragments = 5; /// /// The material for the fragments. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public ProtoId FragmentStackProtoId = "ArtifactFragment"; /// @@ -100,12 +102,12 @@ public sealed partial class ArtifactCrusherComponent : Component /// Stores entity of to allow ending it early. /// [DataField] - public (EntityUid, AudioComponent)? CrushingSoundEntity; + public EntityUid? CrushingSoundEntity; /// /// When enabled, stops the artifact crusher from being opened when it is being crushed. /// - [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public bool AutoLock = false; } diff --git a/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactCrusherSystem.cs b/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactCrusherSystem.cs index 64f3126297..a8c4b9ff06 100644 --- a/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactCrusherSystem.cs +++ b/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactCrusherSystem.cs @@ -1,9 +1,16 @@ -using Content.Shared.Examine; -using Content.Shared.Storage.Components; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Containers; +using Content.Shared.Damage; using Content.Shared.Emag.Systems; +using Content.Shared.Examine; +using Content.Shared.Popups; +using Content.Shared.Power; +using Content.Shared.Power.EntitySystems; +using Content.Shared.Storage.Components; +using Content.Shared.Verbs; using Content.Shared.Xenoarchaeology.Equipment.Components; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Collections; +using Robust.Shared.Containers; +using Robust.Shared.Timing; namespace Content.Shared.Xenoarchaeology.Equipment; @@ -12,10 +19,14 @@ namespace Content.Shared.Xenoarchaeology.Equipment; /// public abstract class SharedArtifactCrusherSystem : EntitySystem { - [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] protected readonly SharedAudioSystem AudioSystem = default!; [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly SharedPowerReceiverSystem _power = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly DamageableSystem _damageable = default!; /// public override void Initialize() @@ -27,6 +38,8 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem SubscribeLocalEvent(OnStorageOpenAttempt); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnEmagged); + SubscribeLocalEvent>(OnGetVerbs); + SubscribeLocalEvent(OnPowerChanged); } private void OnInit(Entity ent, ref ComponentInit args) @@ -53,6 +66,7 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem ent.Comp.AutoLock = true; args.Handled = true; + Dirty(ent); } private void OnStorageOpenAttempt(Entity ent, ref StorageOpenAttemptEvent args) @@ -66,22 +80,94 @@ public abstract class SharedArtifactCrusherSystem : EntitySystem args.PushMarkup(ent.Comp.AutoLock ? Loc.GetString("artifact-crusher-examine-autolocks") : Loc.GetString("artifact-crusher-examine-no-autolocks")); } - public void StopCrushing(Entity ent, bool early = true) + private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) { - var (_, crusher) = ent; - - if (!crusher.Crushing) + if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing) return; - crusher.Crushing = false; - Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, false); + if (!TryComp(ent, out var entityStorageComp) || + entityStorageComp.Contents.ContainedEntities.Count == 0) + return; + + if (!_power.IsPowered(ent.Owner)) + return; + + var user = args.User; + var verb = new AlternativeVerb + { + Text = Loc.GetString("artifact-crusher-verb-start-crushing"), + Priority = 2, + Act = () => StartCrushing((ent, ent.Comp, entityStorageComp), user) + }; + args.Verbs.Add(verb); + } + + private void OnPowerChanged(Entity ent, ref PowerChangedEvent args) + { + if (!args.Powered) + StopCrushing(ent); + } + + public void StartCrushing(Entity ent, EntityUid? user = null) + { + var (uid, crusher, _) = ent; + + if (crusher.Crushing) + return; + + if (crusher.AutoLock) + _popup.PopupPredicted(Loc.GetString("artifact-crusher-autolocks-enable"), uid, user); + + crusher.Crushing = true; + crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1); + crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration; + crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent)?.Entity; + _appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true); + Dirty(ent, ent.Comp1); + } + + public void StopCrushing(Entity ent, bool early = true) + { + if (!ent.Comp.Crushing) + return; + + ent.Comp.Crushing = false; + _appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, false); if (early) { - AudioSystem.Stop(crusher.CrushingSoundEntity?.Item1, crusher.CrushingSoundEntity?.Item2); - crusher.CrushingSoundEntity = null; + AudioSystem.Stop(ent.Comp.CrushingSoundEntity); + ent.Comp.CrushingSoundEntity = null; } Dirty(ent, ent.Comp); } + + public virtual void FinishCrushing(Entity ent) { } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var crusher, out var storage)) + { + if (!crusher.Crushing) + continue; + + if (crusher.NextSecond < _timing.CurTime) + { + var contents = new ValueList(storage.Contents.ContainedEntities); + foreach (var contained in contents) + { + _damageable.TryChangeDamage(contained, crusher.CrushingDamage); + } + crusher.NextSecond += TimeSpan.FromSeconds(1); + Dirty(uid, crusher); + } + + if (crusher.CrushEndTime < _timing.CurTime) + FinishCrushing((uid, crusher, storage)); + } + } }