]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Bomb Deliveries (#37069)
authorScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Sun, 18 May 2025 08:57:22 +0000 (10:57 +0200)
committerGitHub <noreply@github.com>
Sun, 18 May 2025 08:57:22 +0000 (10:57 +0200)
* init

* BOMB!!!

* review

* partial review

* review

12 files changed:
Content.Client/Delivery/DeliveryVisualizerSystem.cs
Content.Shared/Delivery/DeliveryBombComponent.cs [new file with mode: 0644]
Content.Shared/Delivery/DeliveryModifierSystem.cs
Content.Shared/Delivery/DeliveryVisuals.cs
Content.Shared/Delivery/PrimedDeliveryBombComponent.cs [new file with mode: 0644]
Content.Shared/Delivery/SharedDeliverySystem.cs
Resources/Locale/en-US/delivery/delivery-component.ftl
Resources/Prototypes/Entities/Objects/Deliveries/deliveries.yml
Resources/Textures/Objects/Specific/Cargo/mail.rsi/bomb_unshaded.png [moved from Resources/Textures/Objects/Specific/Cargo/mail.rsi/bomb-unshaded.png with 100% similarity]
Resources/Textures/Objects/Specific/Cargo/mail.rsi/meta.json
Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/bomb_unshaded.png [moved from Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/bomb-unshaded.png with 100% similarity]
Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/meta.json

index bf4a8f066b4d7dc97619f6d67a8fcba3f018a535..68149e248d68488594ae352a96f5b4219ea977c8 100644 (file)
@@ -42,6 +42,8 @@ public enum DeliveryVisualLayers : byte
     PriorityTape,
     Breakage,
     Trash,
+    Bomb,
+    BombPrimed,
 }
 
 public enum DeliverySpawnerVisualLayers : byte
diff --git a/Content.Shared/Delivery/DeliveryBombComponent.cs b/Content.Shared/Delivery/DeliveryBombComponent.cs
new file mode 100644 (file)
index 0000000..a51bb83
--- /dev/null
@@ -0,0 +1,65 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Delivery;
+
+/// <summary>
+/// Component given to deliveries.
+/// This delivery will "prime" based on circumstances defined in the datafield.
+/// When primed, it will attempt to explode every few seconds, with the chance increasing each time it fails to do so.
+/// </summary>
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
+[Access(typeof(DeliveryModifierSystem))]
+public sealed partial class DeliveryBombComponent : Component
+{
+    /// <summary>
+    /// How often will this bomb retry to explode.
+    /// </summary>
+    [DataField]
+    public TimeSpan ExplosionRetryDelay = TimeSpan.FromSeconds(5);
+
+    /// <summary>
+    /// The time at which the next retry will happen
+    /// </summary>
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
+    public TimeSpan NextExplosionRetry;
+
+    /// <summary>
+    /// The chance this bomb explodes each time it attempts to do so.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public float ExplosionChance = 0.01f;
+
+    /// <summary>
+    /// How much should the chance of explosion increase each failed retry?
+    /// </summary>
+    [DataField]
+    public float ExplosionChanceRetryIncrease = 0.01f;
+
+    /// <summary>
+    /// Should this bomb get primed when the delivery is unlocked?
+    /// </summary>
+    [DataField]
+    public bool PrimeOnUnlock = true;
+
+    /// <summary>
+    /// Should this bomb get primed when the delivery is broken?
+    /// Requires to be fragile as well.
+    /// </summary>
+    [DataField]
+    public bool PrimeOnBreakage = true;
+
+    /// <summary>
+    /// Should this bomb get primed when the delivery expires?
+    /// Requires to be priority as well.
+    /// </summary>
+    [DataField]
+    public bool PrimeOnExpire = true;
+
+    /// <summary>
+    /// Multiplier to choose when a crazy person actually opens it.
+    /// Multiplicative, not additive.
+    /// </summary>
+    [DataField]
+    public float SpesoMultiplier = 1.5f;
+}
index 2b071b18cfb9106fbdb1e38473f2c3c0131dcd22..0e3f620f26812541a3e143398e80982c3789eeee 100644 (file)
@@ -1,6 +1,10 @@
+using Content.Shared.Audio;
 using Content.Shared.Destructible;
 using Content.Shared.Examine;
+using Content.Shared.Explosion.EntitySystems;
 using Content.Shared.NameModifier.EntitySystems;
+using JetBrains.Annotations;
+using Robust.Shared.Network;
 using Robust.Shared.Random;
 using Robust.Shared.Serialization;
 using Robust.Shared.Timing;
@@ -14,8 +18,11 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
 {
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly IGameTiming _timing = default!;
+    [Dependency] private readonly INetManager _net = default!;
     [Dependency] private readonly NameModifierSystem _nameModifier = default!;
     [Dependency] private readonly SharedDeliverySystem _delivery = default!;
+    [Dependency] private readonly SharedExplosionSystem _explosion = default!;
+    [Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!;
 
     public override void Initialize()
     {
@@ -33,6 +40,14 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
         SubscribeLocalEvent<DeliveryFragileComponent, BreakageEventArgs>(OnFragileBreakage);
         SubscribeLocalEvent<DeliveryFragileComponent, ExaminedEvent>(OnFragileExamine);
         SubscribeLocalEvent<DeliveryFragileComponent, GetDeliveryMultiplierEvent>(OnGetFragileMultiplier);
+
+        SubscribeLocalEvent<DeliveryBombComponent, ComponentStartup>(OnExplosiveStartup);
+        SubscribeLocalEvent<PrimedDeliveryBombComponent, MapInitEvent>(OnPrimedExplosiveMapInit);
+        SubscribeLocalEvent<DeliveryBombComponent, ExaminedEvent>(OnExplosiveExamine);
+        SubscribeLocalEvent<DeliveryBombComponent, GetDeliveryMultiplierEvent>(OnGetExplosiveMultiplier);
+        SubscribeLocalEvent<DeliveryBombComponent, DeliveryUnlockedEvent>(OnExplosiveUnlock);
+        SubscribeLocalEvent<DeliveryBombComponent, DeliveryPriorityExpiredEvent>(OnExplosiveExpire);
+        SubscribeLocalEvent<DeliveryBombComponent, BreakageEventArgs>(OnExplosiveBreak);
     }
 
     #region Random
@@ -119,12 +134,80 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
     }
     #endregion
 
+    #region Explosive
+    private void OnExplosiveStartup(Entity<DeliveryBombComponent> ent, ref ComponentStartup args)
+    {
+        _delivery.UpdateBombVisuals(ent);
+    }
+
+    private void OnPrimedExplosiveMapInit(Entity<PrimedDeliveryBombComponent> ent, ref MapInitEvent args)
+    {
+        if (!TryComp<DeliveryBombComponent>(ent, out var bomb))
+            return;
+
+        bomb.NextExplosionRetry = _timing.CurTime;
+    }
+
+    private void OnExplosiveExamine(Entity<DeliveryBombComponent> ent, ref ExaminedEvent args)
+    {
+        var trueName = _nameModifier.GetBaseName(ent.Owner);
+
+        var isPrimed = HasComp<PrimedDeliveryBombComponent>(ent);
+
+        if (isPrimed)
+            args.PushMarkup(Loc.GetString("delivery-bomb-primed-examine", ("type", trueName)));
+        else
+            args.PushMarkup(Loc.GetString("delivery-bomb-examine", ("type", trueName)));
+    }
+
+    private void OnGetExplosiveMultiplier(Entity<DeliveryBombComponent> ent, ref GetDeliveryMultiplierEvent args)
+    {
+        // Big danger for big rewards
+        args.MultiplicativeMultiplier += ent.Comp.SpesoMultiplier;
+    }
+
+    private void OnExplosiveUnlock(Entity<DeliveryBombComponent> ent, ref DeliveryUnlockedEvent args)
+    {
+        if (!ent.Comp.PrimeOnUnlock)
+            return;
+
+        PrimeBombDelivery(ent);
+    }
+
+    private void OnExplosiveExpire(Entity<DeliveryBombComponent> ent, ref DeliveryPriorityExpiredEvent args)
+    {
+        if (!ent.Comp.PrimeOnExpire)
+            return;
+
+        PrimeBombDelivery(ent);
+    }
+
+    private void OnExplosiveBreak(Entity<DeliveryBombComponent> ent, ref BreakageEventArgs args)
+    {
+        if (!ent.Comp.PrimeOnBreakage)
+            return;
+
+        PrimeBombDelivery(ent);
+    }
+
+    [PublicAPI]
+    public void PrimeBombDelivery(Entity<DeliveryBombComponent> ent)
+    {
+        EnsureComp<PrimedDeliveryBombComponent>(ent);
+
+        _delivery.UpdateBombVisuals(ent);
+
+        _ambientSound.SetAmbience(ent, true);
+    }
+    #endregion
+
     #region Update Loops
     public override void Update(float frameTime)
     {
         base.Update(frameTime);
 
         UpdatePriorty(frameTime);
+        UpdateBomb(frameTime);
     }
 
     private void UpdatePriorty(float frameTime)
@@ -148,6 +231,27 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
             }
         }
     }
+
+    private void UpdateBomb(float frameTime)
+    {
+        var bombQuery = EntityQueryEnumerator<PrimedDeliveryBombComponent, DeliveryBombComponent>();
+        var curTime = _timing.CurTime;
+
+        while (bombQuery.MoveNext(out var uid, out _, out var bombData))
+        {
+            if (bombData.NextExplosionRetry > curTime)
+                continue;
+
+            bombData.NextExplosionRetry += bombData.ExplosionRetryDelay;
+
+            // Explosions cannot be predicted.
+            if (_net.IsServer && _random.NextFloat() < bombData.ExplosionChance)
+                _explosion.TriggerExplosive(uid);
+
+            bombData.ExplosionChance += bombData.ExplosionChanceRetryIncrease;
+            Dirty(uid, bombData);
+        }
+    }
     #endregion
 }
 
index 35391854beaa8b74879cd8cced44891622488375..b63d6a20bb4b6574bd23a5b8436fb86a84d87d26 100644 (file)
@@ -9,6 +9,7 @@ public enum DeliveryVisuals : byte
     IsTrash,
     IsBroken,
     IsFragile,
+    IsBomb,
     PriorityState,
     JobIcon,
 }
@@ -21,6 +22,14 @@ public enum DeliveryPriorityState : byte
     Inactive,
 }
 
+[Serializable, NetSerializable]
+public enum DeliveryBombState : byte
+{
+    Off,
+    Inactive,
+    Primed,
+}
+
 [Serializable, NetSerializable]
 public enum DeliverySpawnerVisuals : byte
 {
diff --git a/Content.Shared/Delivery/PrimedDeliveryBombComponent.cs b/Content.Shared/Delivery/PrimedDeliveryBombComponent.cs
new file mode 100644 (file)
index 0000000..f3fd124
--- /dev/null
@@ -0,0 +1,11 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Delivery;
+
+/// <summary>
+/// Component given to deliveries.
+/// Indicates this bomb delivery is primed.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(DeliveryModifierSystem))]
+public sealed partial class PrimedDeliveryBombComponent : Component;
index 175dfbe70d011446fa82a7df2ad66204855b9a9a..52f83500e14d004d298d60020a742b2946c97b67 100644 (file)
@@ -259,6 +259,13 @@ public abstract class SharedDeliverySystem : EntitySystem
         _appearance.SetData(ent, DeliveryVisuals.IsFragile, isFragile);
     }
 
+    public void UpdateBombVisuals(Entity<DeliveryBombComponent> ent)
+    {
+        var isPrimed = HasComp<PrimedDeliveryBombComponent>(ent);
+
+        _appearance.SetData(ent, DeliveryVisuals.IsBomb, isPrimed ? DeliveryBombState.Primed : DeliveryBombState.Inactive);
+    }
+
     protected void UpdateDeliverySpawnerVisuals(EntityUid uid, int contents)
     {
         _appearance.SetData(uid, DeliverySpawnerVisuals.Contents, contents > 0);
index c346b2a813b510e1c21c6e58d6a431c47be0ff4c..306dd9b04432092644725ff1135a4027905486a8 100644 (file)
@@ -29,3 +29,6 @@ delivery-priority-expired-examine = This is a [color=orange]priority {$type}[/co
 
 delivery-fragile-examine = This is a [color=red]fragile {$type}[/color]. Deliver it intact for a bonus.
 delivery-fragile-broken-examine = This is a [color=red]fragile {$type}[/color]. It looks badly damaged.
+
+delivery-bomb-examine = This is a [color=purple]bomb {$type}[/color]. Oh no.
+delivery-bomb-primed-examine = This is a [color=purple]bomb {$type}[/color]. Reading this is a bad use of your time.
index a209f5c6f758b59bab1b459711b023a3e02122dc..acf88fc8b34d404954b1d3a10654e2d1a7d5e37b 100644 (file)
         enum.DeliveryVisualLayers.Trash:
           True: { visible: true }
           False: { visible: false }
+      enum.DeliveryVisuals.IsBomb:
+        enum.DeliveryVisualLayers.Bomb:
+          Off: { visible: false }
+          Inactive: { visible: true }
+          Primed: { visible: true }
+        enum.DeliveryVisualLayers.BombPrimed:
+          Off: { visible: false }
+          Inactive: { visible: false }
+          Primed: { visible: true }
   - type: Label
     examinable: false
   - type: FingerprintReader
     - state: broken
       map: [ "enum.DeliveryVisualLayers.Breakage" ]
       visible: false
+    - state: bomb
+      map: [ "enum.DeliveryVisualLayers.Bomb" ]
+      visible: false
+    - state: bomb_unshaded
+      map: [ "enum.DeliveryVisualLayers.BombPrimed" ]
+      shader: unshaded
+      visible: false
   - type: MultiHandedItem
   - type: Item
     size: Huge
     - state: broken
       map: [ "enum.DeliveryVisualLayers.Breakage" ]
       visible: false
+    - state: bomb
+      map: [ "enum.DeliveryVisualLayers.Bomb" ]
+      visible: false
+    - state: bomb_unshaded
+      map: [ "enum.DeliveryVisualLayers.BombPrimed" ]
+      shader: unshaded
+      visible: false
   - type: Item
     storedRotation: 90
   - type: Delivery
       prob: 0.25
     - id: DeliveryModifierFragile
       prob: 0.25
+    - id: DeliveryModifierBomb
+      prob: 0.02 # Should happen maybe once or twice per game.
 
 - type: entity
   id: DeliveryModifierPriority
           collection: DeliveryOpenSounds
       - !type:DoActsBehavior
         acts: [ "Breakage" ]
+
+- type: entity
+  id: DeliveryModifierBomb
+  description: Components to add when a delivery is rolled as a bomb.
+  categories: [ HideSpawnMenu ]
+  components:
+  - type: DeliveryBomb
+  - type: AmbientSound
+    enabled: false
+    range: 8
+    sound:
+      path: /Audio/Effects/lightburn.ogg
+  - type: Explosive
+    explosionType: MicroBomb
+    totalIntensity: 120
+    intensitySlope: 4
+    maxIntensity: 30
+    canCreateVacuum: false
index 9aa97992b1517bcba835cd6bd305162f3dbd5123..500d1632fc1dd1f1f9b5adfabb2dfbaa0dc09da3 100644 (file)
@@ -43,7 +43,7 @@
             "name": "bomb"
         },
         {
-            "name": "bomb-unshaded",
+            "name": "bomb_unshaded",
             "delays": [
                 [
                     0.2,
index a265c4aada8a72257cbd8b691473c12397437867..67fafe31b3f90af61ab27edaf2e044b16f4acdd6 100644 (file)
@@ -43,7 +43,7 @@
             "name": "bomb"
         },
         {
-            "name": "bomb-unshaded",
+            "name": "bomb_unshaded",
             "delays": [
                 [
                     0.125,