using Content.Shared.ActionBlocker; using Content.Shared.Emoting; using Content.Shared.Interaction.Events; using Content.Shared.Item; using Content.Shared.Movement.Events; using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Events; using Content.Shared.Movement.Pulling.Systems; using Content.Shared.Speech; using Content.Shared.Throwing; namespace Content.Shared._Starlight.Actions.Stasis; /// /// System that handles the freezing behavior of entities in stasis. /// This system prevents entities with StasisFrozenComponent from performing most actions, /// while still allowing them to use the exit stasis action. /// public abstract class SharedStasisFrozenSystem : EntitySystem { [Dependency] private readonly ActionBlockerSystem _blocker = default!; [Dependency] private readonly PullingSystem _pulling = default!; public override void Initialize() { base.Initialize(); // Block various actions and interactions SubscribeLocalEvent(OnUseAttempt); SubscribeLocalEvent(OnCancellableAttempt); SubscribeLocalEvent(OnCancellableAttempt); SubscribeLocalEvent(OnInteractAttempt); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(UpdateCanMove); SubscribeLocalEvent(OnUpdateCanMove); SubscribeLocalEvent(OnPullAttempt); SubscribeLocalEvent(OnCancellableAttempt); SubscribeLocalEvent(OnCancellableAttempt); SubscribeLocalEvent(OnEmoteAttempt); SubscribeLocalEvent(OnSpeakAttempt); } /// /// Handles use attempts, allowing only the exit stasis action to proceed. /// private void OnUseAttempt(EntityUid uid, StasisFrozenComponent component, UseAttemptEvent args) { // If we get here, the entity with StasisFrozenComponent is trying to use an action if (!TryComp(uid, out var stasisComponent)) { args.Cancel(); return; } // Check if this is the exit stasis action if (stasisComponent.ExitStasisActionEntity != null && args.Used == stasisComponent.ExitStasisActionEntity) { // Allow the exit stasis action to proceed return; } args.Cancel(); } /// /// Handles speech attempts, blocking them if the entity is muted. /// private void OnSpeakAttempt(EntityUid uid, StasisFrozenComponent component, SpeakAttemptEvent args) { if (!component.Muted) { return; } args.Cancel(); } /// /// Handles various cancellable attempts, blocking them all. /// private void OnCancellableAttempt(EntityUid uid, StasisFrozenComponent component, CancellableEntityEventArgs args) { args.Cancel(); } /// /// Handles pull attempts, preventing the entity from being pulled. /// private void OnPullAttempt(EntityUid uid, StasisFrozenComponent component, PullAttemptEvent args) { args.Cancelled = true; } /// /// Handles component startup, stopping any active pulls and updating movement state. /// private void OnStartup(EntityUid uid, StasisFrozenComponent component, ComponentStartup args) { if (TryComp(uid, out var pullable)) { _pulling.TryStopPull(uid, pullable); } UpdateCanMove(uid, component, args); } /// /// Handles movement update events, preventing movement while in stasis. /// private void OnUpdateCanMove(EntityUid uid, StasisFrozenComponent component, UpdateCanMoveEvent args) { if (component.LifeStage > ComponentLifeStage.Running) return; args.Cancel(); } /// /// Updates the entity's movement state. /// private void UpdateCanMove(EntityUid uid, StasisFrozenComponent component, EntityEventArgs args) { _blocker.UpdateCanMove(uid); } /// /// Handles emote attempts, blocking them if the entity is muted. /// private void OnEmoteAttempt(EntityUid uid, StasisFrozenComponent component, EmoteAttemptEvent args) { if (component.Muted) { args.Cancel(); } } /// /// Handles general interaction attempts, blocking them all except for skills. /// private void OnInteractAttempt(Entity ent, ref InteractionAttemptEvent args) { // Check if this is a skill interaction if (args.Target == null) { return; } // Block all other interactions args.Cancelled = true; } }