]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Use distinct action labels for toggling internals on and off. (#36073)
authorCiarán Walsh <github@ciaranwal.sh>
Mon, 2 Jun 2025 11:09:45 +0000 (12:09 +0100)
committerGitHub <noreply@github.com>
Mon, 2 Jun 2025 11:09:45 +0000 (13:09 +0200)
* Use distinct action labels for toggling internals on and off.

* Implement specific actions for enabling/disabling internals

Avoids potential confusing race conditions where two people might perform the "Toggle Internals On" action an the same person,
which would have jsut toggled twice.

* If no gas tank, will give popup

---------

Co-authored-by: beck-thompson <beck314159@hotmail.com>
Content.Server/Body/Systems/InternalsSystem.cs
Content.Shared/Body/Systems/SharedInternalsSystem.cs
Content.Shared/Internals/InternalsDoAfterEvent.cs
Resources/Locale/en-US/actions/actions/internals.ftl

index 29c2c363d29b61f136ef0484d9b033a94f705344..93dedf5ffffc698eded0fb18956a6a5b519bb846 100644 (file)
@@ -50,7 +50,7 @@ public sealed class InternalsSystem : SharedInternalsSystem
         if (!_respirator.CanMetabolizeGas(uid, tank.Value.Comp.Air))
             return;
 
-        ToggleInternals(uid, uid, force: false, component);
+        ToggleInternals(uid, uid, force: false, component, ToggleMode.On);
     }
 
     private void OnInhaleLocation(Entity<InternalsComponent> ent, ref InhaleLocationEvent args)
index 0924d7a99efa5c5d76825ca5142cafeae24525e3..7749432281e3f3cf93d79d6fee46fb90f3cdb617 100644 (file)
@@ -4,6 +4,7 @@ using Content.Shared.Atmos.EntitySystems;
 using Content.Shared.Body.Components;
 using Content.Shared.DoAfter;
 using Content.Shared.Hands.Components;
+using Content.Shared.IdentityManagement;
 using Content.Shared.Internals;
 using Content.Shared.Inventory;
 using Content.Shared.Popups;
@@ -50,73 +51,91 @@ public abstract class SharedInternalsSystem : EntitySystem
 
         InteractionVerb verb = new()
         {
-            Act = () =>
-            {
-                ToggleInternals(ent, user, force: false, ent);
-            },
-            Message = Loc.GetString("action-description-internals-toggle"),
             Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/dot.svg.192dpi.png")),
-            Text = Loc.GetString("action-name-internals-toggle"),
         };
 
+        if (AreInternalsWorking(ent))
+        {
+            verb.Act = () => ToggleInternals(ent, user, force: false, ent, ToggleMode.Off);
+            verb.Message = Loc.GetString("action-description-internals-toggle-off");
+            verb.Text = Loc.GetString("action-name-internals-toggle-off");
+        }
+        else
+        {
+            verb.Act = () => ToggleInternals(ent, user, force: false, ent, ToggleMode.On);
+            verb.Message = Loc.GetString("action-description-internals-toggle-on");
+            verb.Text = Loc.GetString("action-name-internals-toggle-on");
+        }
+
         args.Verbs.Add(verb);
     }
 
-    public bool ToggleInternals(
-        EntityUid uid,
+    protected bool ToggleInternals(
+        EntityUid target,
         EntityUid user,
         bool force,
-        InternalsComponent? internals = null)
+        InternalsComponent? internals = null,
+        ToggleMode mode = ToggleMode.Toggle)
     {
-        if (!Resolve(uid, ref internals, logMissing: false))
+        if (!Resolve(target, ref internals, logMissing: false))
             return false;
 
         // Check if a mask is present.
         if (internals.BreathTools.Count == 0)
         {
-            _popupSystem.PopupClient(Loc.GetString("internals-no-breath-tool"), uid, user);
+            var message = user == target ? Loc.GetString("internals-self-no-breath-tool") : Loc.GetString("internals-other-no-breath-tool", ("ent", Identity.Name(target, EntityManager, user)));
+            _popupSystem.PopupClient(message, target, user);
+            return false;
+        }
+
+        // Check if tank is present.
+        var tank = FindBestGasTank(target);
+
+        // If they're not on then check if we have a mask to use
+        if (tank == null)
+        {
+            var message = user == target ? Loc.GetString("internals-self-no-tank") : Loc.GetString("internals-other-no-tank", ("ent", Identity.Name(target, EntityManager, user)));
+            _popupSystem.PopupClient(message, target, user);
             return false;
         }
 
         // Start the toggle do-after if it's on someone else.
-        if (!force && user != uid)
+        if (!force && user != target)
         {
-            return StartToggleInternalsDoAfter(user, (uid, internals));
+            return StartToggleInternalsDoAfter(user, (target, internals), mode);
         }
 
         // Toggle off.
         if (TryComp(internals.GasTankEntity, out GasTankComponent? gas))
         {
+            if (mode == ToggleMode.On)
+                return false;
+
             return _gasTank.DisconnectFromInternals((internals.GasTankEntity.Value, gas), user);
         }
-        else
-        {
-            // Check if tank is present.
-            var tank = FindBestGasTank(uid);
 
-            // If they're not on then check if we have a mask to use
-            if (tank == null)
-            {
-                _popupSystem.PopupClient(Loc.GetString("internals-no-tank"), uid, user);
-                return false;
-            }
+        // No tank was connected, we’ll try to toggle internals on
 
-            return _gasTank.ConnectToInternals(tank.Value, user: user);
-        }
+        // If the intent was to disable internals there’s nothing left to do
+        if (mode == ToggleMode.Off)
+            return false;
+
+        return _gasTank.ConnectToInternals(tank.Value, user: user);
     }
 
-    private bool StartToggleInternalsDoAfter(EntityUid user, Entity<InternalsComponent> targetEnt)
+    private bool StartToggleInternalsDoAfter(EntityUid user, Entity<InternalsComponent> targetEnt, ToggleMode mode)
     {
         // Is the target not you? If yes, use a do-after to give them time to respond.
         var isUser = user == targetEnt.Owner;
         var delay = !isUser ? targetEnt.Comp.Delay : TimeSpan.Zero;
 
-        return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(), targetEnt, target: targetEnt)
-        {
-            BreakOnDamage = true,
-            BreakOnMove =  true,
-            MovementThreshold = 0.1f,
-        });
+        return _doAfter.TryStartDoAfter(
+            new DoAfterArgs(EntityManager, user, delay, new InternalsDoAfterEvent(mode), targetEnt, target: targetEnt)
+            {
+                BreakOnDamage = true,
+                BreakOnMove = true,
+                MovementThreshold = 0.1f,
+            });
     }
 
     private void OnDoAfter(Entity<InternalsComponent> ent, ref InternalsDoAfterEvent args)
@@ -124,7 +143,7 @@ public abstract class SharedInternalsSystem : EntitySystem
         if (args.Cancelled || args.Handled)
             return;
 
-        ToggleInternals(ent, args.User, force: true, ent);
+        ToggleInternals(ent, args.User, force: true, ent, args.ToggleMode);
 
         args.Handled = true;
     }
index 9c0174b4fd20ea9b7999af88c9f5005c42779ee7..66c2bd9327f62fa318f18ec425dc7f7d84817d6b 100644 (file)
@@ -4,9 +4,24 @@ using Robust.Shared.Serialization;
 
 namespace Content.Shared.Internals;
 
+public enum ToggleMode
+{
+    Toggle,
+    On,
+    Off
+}
+
 [Serializable, NetSerializable]
-public sealed partial class InternalsDoAfterEvent : SimpleDoAfterEvent
+public sealed partial class InternalsDoAfterEvent : DoAfterEvent
 {
+    public ToggleMode ToggleMode = ToggleMode.Toggle;
+
+    public InternalsDoAfterEvent(ToggleMode mode)
+    {
+        ToggleMode = mode;
+    }
+
+    public override DoAfterEvent Clone() => this;
 }
 
 public sealed partial class ToggleInternalsAlertEvent : BaseAlertEvent;
index ead73cf1e57854c8f78d8442d73544fdd76035e1..e55a51f3d5b3e24f76a75f9a9343896900e4aca7 100644 (file)
@@ -1,5 +1,9 @@
-action-name-internals-toggle = Toggle Internals
-action-description-internals-toggle = Breathe from the equipped gas tank. Also requires equipped breath mask.
+action-name-internals-toggle-on = Toggle Internals On
+action-description-internals-toggle-on = Breathe from the equipped gas tank. Also requires equipped breath mask.
+action-name-internals-toggle-off = Toggle Internals Off
+action-description-internals-toggle-off = Breathe from the environment.
 
-internals-no-breath-tool = You are not wearing a breathing tool
-internals-no-tank = You are not wearing a gas tank
+internals-self-no-breath-tool = You are not wearing a breathing tool
+internals-other-no-breath-tool = {$ent} is not wearing a breathing tool
+internals-self-no-tank = You are not wearing a gas tank
+internals-other-no-tank = {$ent} is not wearing a gas tank