]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Prevent pacified players from throwing dangerous stuff (#22268)
authorKP <13428215+nok-ko@users.noreply.github.com>
Mon, 11 Dec 2023 23:40:22 +0000 (15:40 -0800)
committerGitHub <noreply@github.com>
Mon, 11 Dec 2023 23:40:22 +0000 (15:40 -0800)
Content.Server/Damage/Systems/DamageOnLandSystem.cs
Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs
Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs
Content.Server/Hands/Systems/HandsSystem.cs
Content.Shared/CombatMode/Pacification/PacificationSystem.cs
Content.Shared/CombatMode/Pacification/PacifiedComponent.cs
Content.Shared/Projectiles/SharedProjectileSystem.cs
Content.Shared/Throwing/BeforeThrowEvent.cs
Resources/Locale/en-US/pacified/pacified.ftl [new file with mode: 0644]

index f44bfeacce4eb9e6b2150a1647f37ae648050886..8f01e791ead4d1d206ef757a0d8699860564fec8 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Server.Damage.Components;
+using Content.Shared.CombatMode.Pacification;
 using Content.Shared.Damage;
 using Content.Shared.Throwing;
 
@@ -12,6 +13,19 @@ namespace Content.Server.Damage.Systems
         {
             base.Initialize();
             SubscribeLocalEvent<DamageOnLandComponent, LandEvent>(DamageOnLand);
+            SubscribeLocalEvent<DamageOnLandComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
+        }
+
+        /// <summary>
+        /// Prevent Pacified entities from throwing damaging items.
+        /// </summary>
+        private void OnAttemptPacifiedThrow(Entity<DamageOnLandComponent> ent, ref AttemptPacifiedThrowEvent args)
+        {
+            // Allow healing projectiles, forbid any that do damage:
+            if (ent.Comp.Damage.Any())
+            {
+                args.Cancel("pacified-cannot-throw");
+            }
         }
 
         private void DamageOnLand(EntityUid uid, DamageOnLandComponent component, ref LandEvent args)
index b04c1296fcfa5aa1f7b8f968b2a696b9cf26393a..f355187a0b0af5d83953583cc2b080f4a2d5fed6 100644 (file)
@@ -2,6 +2,7 @@ using System.Linq;
 using Content.Server.Body.Systems;
 using Content.Shared.Alert;
 using Content.Shared.Body.Part;
+using Content.Shared.CombatMode.Pacification;
 using Content.Shared.Damage.Components;
 using Content.Shared.Damage.Systems;
 using Content.Shared.DoAfter;
@@ -26,6 +27,12 @@ public sealed partial class EnsnareableSystem
         SubscribeLocalEvent<EnsnaringComponent, StepTriggerAttemptEvent>(AttemptStepTrigger);
         SubscribeLocalEvent<EnsnaringComponent, StepTriggeredEvent>(OnStepTrigger);
         SubscribeLocalEvent<EnsnaringComponent, ThrowDoHitEvent>(OnThrowHit);
+        SubscribeLocalEvent<EnsnaringComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
+    }
+
+    private void OnAttemptPacifiedThrow(Entity<EnsnaringComponent> ent, ref AttemptPacifiedThrowEvent args)
+    {
+        args.Cancel("pacified-cannot-throw-snare");
     }
 
     private void OnComponentRemove(EntityUid uid, EnsnaringComponent component, ComponentRemove args)
index a6d6a5b2043ed88b3fa6ca81b10c2dd1526b3636..78bdfc6d06eef3fcdd8028c2f41fda5351536dc9 100644 (file)
@@ -6,6 +6,7 @@ using Content.Shared.Chemistry.EntitySystems;
 using Content.Shared.Chemistry.Reaction;
 using Content.Shared.Chemistry.Reagent;
 using Content.Shared.Clothing.Components;
+using Content.Shared.CombatMode.Pacification;
 using Content.Shared.Database;
 using Content.Shared.DoAfter;
 using Content.Shared.Examine;
@@ -36,6 +37,7 @@ public sealed partial class PuddleSystem
         SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
         SubscribeLocalEvent<SpillableComponent, SolutionOverflowEvent>(OnOverflow);
         SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
+        SubscribeLocalEvent<SpillableComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
     }
 
     private void OnExamined(EntityUid uid, SpillableComponent component, ExaminedEvent args)
@@ -152,6 +154,22 @@ public sealed partial class PuddleSystem
         TrySplashSpillAt(uid, Transform(uid).Coordinates, drainedSolution, out _);
     }
 
+    /// <summary>
+    /// Prevent Pacified entities from throwing items that can spill liquids.
+    /// </summary>
+    private void OnAttemptPacifiedThrow(Entity<SpillableComponent> ent, ref AttemptPacifiedThrowEvent args)
+    {
+        // Don’t care about closed containers.
+        if (_openable.IsClosed(ent))
+            return;
+
+        // Don’t care about empty containers.
+        if (!_solutionContainerSystem.TryGetSolution(ent, ent.Comp.SolutionName, out var solution))
+            return;
+
+        args.Cancel("pacified-cannot-throw-spill");
+    }
+
     private void AddSpillVerb(EntityUid uid, SpillableComponent component, GetVerbsEvent<Verb> args)
     {
         if (!args.CanAccess || !args.CanInteract)
index 5ceb4a8d6048cbf0c9c9f2f39a777f075217ef99..5c750e7544f1ac957fe006a7c798793e68ad28a8 100644 (file)
@@ -204,9 +204,9 @@ namespace Content.Server.Hands.Systems
             // Let other systems change the thrown entity (useful for virtual items)
             // or the throw strength.
             var ev = new BeforeThrowEvent(throwEnt, direction, throwStrength, player);
-            RaiseLocalEvent(player, ev, false);
+            RaiseLocalEvent(player, ref ev);
 
-            if (ev.Handled)
+            if (ev.Cancelled)
                 return true;
 
             // This can grief the above event so we raise it afterwards
index c52605e09f9ef8ed9f9cc955a65a2765b7de81f3..a1332fec76f6a8eef5ce493e0032102ff9fe11b9 100644 (file)
@@ -1,20 +1,57 @@
 using Content.Shared.Actions;
 using Content.Shared.Alert;
+using Content.Shared.IdentityManagement;
 using Content.Shared.Interaction.Events;
+using Content.Shared.Popups;
+using Content.Shared.Throwing;
 
 namespace Content.Shared.CombatMode.Pacification;
 
+/// <summary>
+/// Raised when a Pacified entity attempts to throw something.
+/// The throw is only permitted if this event is not cancelled.
+/// </summary>
+[ByRefEvent]
+public struct AttemptPacifiedThrowEvent
+{
+    public EntityUid ItemUid;
+    public EntityUid PlayerUid;
+
+    public AttemptPacifiedThrowEvent(EntityUid itemUid,  EntityUid playerUid)
+    {
+        ItemUid = itemUid;
+        PlayerUid = playerUid;
+    }
+
+    public bool Cancelled { get; private set; } = false;
+    public string? CancelReasonMessageId { get; private set; }
+
+    /// <param name="reasonMessageId">
+    /// Localization string ID for the reason this event has been cancelled.
+    /// If null, a generic message will be shown to the player.
+    /// Note that any supplied localization string MUST accept a '$projectile'
+    /// parameter specifying the name of the thrown entity.
+    /// </param>
+    public void Cancel(string? reasonMessageId = null)
+    {
+        Cancelled = true;
+        CancelReasonMessageId = reasonMessageId;
+    }
+}
+
 public sealed class PacificationSystem : EntitySystem
 {
     [Dependency] private readonly AlertsSystem _alertsSystem = default!;
     [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
     [Dependency] private readonly SharedCombatModeSystem _combatSystem = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
 
     public override void Initialize()
     {
         base.Initialize();
         SubscribeLocalEvent<PacifiedComponent, ComponentStartup>(OnStartup);
         SubscribeLocalEvent<PacifiedComponent, ComponentShutdown>(OnShutdown);
+        SubscribeLocalEvent<PacifiedComponent, BeforeThrowEvent>(OnBeforeThrow);
         SubscribeLocalEvent<PacifiedComponent, AttackAttemptEvent>(OnAttackAttempt);
     }
 
@@ -47,4 +84,23 @@ public sealed class PacificationSystem : EntitySystem
         _actionsSystem.SetEnabled(combatMode.CombatToggleActionEntity, true);
         _alertsSystem.ClearAlert(uid, AlertType.Pacified);
     }
+
+    private void OnBeforeThrow(Entity<PacifiedComponent> ent, ref BeforeThrowEvent args)
+    {
+        var thrownItem = args.ItemUid;
+        var itemName = Identity.Entity(thrownItem, EntityManager);
+
+        // Raise an AttemptPacifiedThrow event and rely on other systems to check
+        // whether the candidate item is OK to throw:
+        var ev = new AttemptPacifiedThrowEvent(thrownItem, ent);
+        RaiseLocalEvent(thrownItem, ref ev);
+        if (!ev.Cancelled)
+            return;
+
+        args.Cancelled = true;
+
+        // Tell the player why they can’t throw stuff:
+        var cannotThrowMessage = ev.CancelReasonMessageId ?? "pacified-cannot-throw";
+        _popup.PopupEntity(Loc.GetString(cannotThrowMessage, ("projectile", itemName)), ent, ent);
+    }
 }
index 40ddc700020e3ef1c85214bfc3ad7700d05e92e4..4b6dff76a2a51a725fe493a8da98ebb90dd4dec4 100644 (file)
@@ -3,7 +3,7 @@ using Robust.Shared.GameStates;
 namespace Content.Shared.CombatMode.Pacification;
 
 /// <summary>
-/// Status effect that disables combat mode.
+/// Status effect that disables combat mode and restricts aggressive actions.
 /// </summary>
 [RegisterComponent, NetworkedComponent]
 [Access(typeof(PacificationSystem))]
index 3b9eded288deaf79b65b36dbc71d645226be4816..e003764f92212c98f815df95376120f909e220ed 100644 (file)
@@ -1,11 +1,10 @@
 using System.Numerics;
+using Content.Shared.CombatMode.Pacification;
 using Content.Shared.Damage;
 using Content.Shared.DoAfter;
 using Content.Shared.Hands.EntitySystems;
 using Content.Shared.Interaction;
 using Content.Shared.Throwing;
-using Content.Shared.Weapons.Ranged.Components;
-using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Map;
 using Robust.Shared.Network;
@@ -37,6 +36,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem
         SubscribeLocalEvent<EmbeddableProjectileComponent, ThrowDoHitEvent>(OnEmbedThrowDoHit);
         SubscribeLocalEvent<EmbeddableProjectileComponent, ActivateInWorldEvent>(OnEmbedActivate);
         SubscribeLocalEvent<EmbeddableProjectileComponent, RemoveEmbeddedProjectileEvent>(OnEmbedRemove);
+        SubscribeLocalEvent<EmbeddableProjectileComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
     }
 
     private void OnEmbedActivate(EntityUid uid, EmbeddableProjectileComponent component, ActivateInWorldEvent args)
@@ -152,6 +152,14 @@ public abstract partial class SharedProjectileSystem : EntitySystem
     {
         public override DoAfterEvent Clone() => this;
     }
+
+    /// <summary>
+    /// Prevent players with the Pacified status effect from throwing embeddable projectiles.
+    /// </summary>
+    private void OnAttemptPacifiedThrow(Entity<EmbeddableProjectileComponent> ent, ref AttemptPacifiedThrowEvent args)
+    {
+        args.Cancel("pacified-cannot-throw-embed");
+    }
 }
 
 [Serializable, NetSerializable]
index 546bf26d8e7a281fb6e53e562ef4be1df0bd63bc..36e7dd758b8fb88349e9d69bb03eac26252a215e 100644 (file)
@@ -1,20 +1,22 @@
 using System.Numerics;
 
-namespace Content.Shared.Throwing
+namespace Content.Shared.Throwing;
+
+[ByRefEvent]
+public struct BeforeThrowEvent
 {
-    public sealed class BeforeThrowEvent : HandledEntityEventArgs
+    public BeforeThrowEvent(EntityUid itemUid, Vector2 direction, float throwStrength,  EntityUid playerUid)
     {
-        public BeforeThrowEvent(EntityUid itemUid, Vector2 direction, float throwStrength,  EntityUid playerUid)
-        {
-           ItemUid = itemUid;
-           Direction = direction;
-           ThrowStrength = throwStrength;
-           PlayerUid = playerUid;
-        }
-
-        public EntityUid ItemUid { get; set; }
-        public Vector2 Direction { get; }
-        public float ThrowStrength { get; set;}
-        public EntityUid PlayerUid { get; }
+        ItemUid = itemUid;
+        Direction = direction;
+        ThrowStrength = throwStrength;
+        PlayerUid = playerUid;
     }
+
+    public EntityUid ItemUid { get; set; }
+    public Vector2 Direction { get; }
+    public float ThrowStrength { get; set;}
+    public EntityUid PlayerUid { get; }
+
+    public bool Cancelled = false;
 }
diff --git a/Resources/Locale/en-US/pacified/pacified.ftl b/Resources/Locale/en-US/pacified/pacified.ftl
new file mode 100644 (file)
index 0000000..4d45f13
--- /dev/null
@@ -0,0 +1,11 @@
+
+## Messages shown to Pacified players when they try to do violence:
+
+# With projectiles:
+pacified-cannot-throw = You can't bring yourself to throw { THE($projectile) }, that could hurt someone!
+# With embedding projectiles:
+pacified-cannot-throw-embed = No way you can throw { THE($projectile) }, that could get lodged inside someone!
+# With liquid-spilling projectiles:
+pacified-cannot-throw-spill = You can't possibly throw { THE($projectile) }, that could spill nasty stuff on someone!
+# With bolas and snares:
+pacified-cannot-throw-snare = You can't throw { THE($projectile) }, what if someone trips?!