From 30537e13a4073c6815d0870465dd6b0e1a6bd83e Mon Sep 17 00:00:00 2001
From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Date: Sun, 18 May 2025 10:57:22 +0200
Subject: [PATCH] Bomb Deliveries (#37069)
* init
* BOMB!!!
* review
* partial review
* review
---
.../Delivery/DeliveryVisualizerSystem.cs | 2 +
.../Delivery/DeliveryBombComponent.cs | 65 +++++++++++
.../Delivery/DeliveryModifierSystem.cs | 104 ++++++++++++++++++
Content.Shared/Delivery/DeliveryVisuals.cs | 9 ++
.../Delivery/PrimedDeliveryBombComponent.cs | 11 ++
.../Delivery/SharedDeliverySystem.cs | 7 ++
.../en-US/delivery/delivery-component.ftl | 3 +
.../Objects/Deliveries/deliveries.yml | 43 ++++++++
.../{bomb-unshaded.png => bomb_unshaded.png} | Bin
.../Objects/Specific/Cargo/mail.rsi/meta.json | 2 +-
.../{bomb-unshaded.png => bomb_unshaded.png} | Bin
.../Specific/Cargo/mail_large.rsi/meta.json | 2 +-
12 files changed, 246 insertions(+), 2 deletions(-)
create mode 100644 Content.Shared/Delivery/DeliveryBombComponent.cs
create mode 100644 Content.Shared/Delivery/PrimedDeliveryBombComponent.cs
rename Resources/Textures/Objects/Specific/Cargo/mail.rsi/{bomb-unshaded.png => bomb_unshaded.png} (100%)
rename Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/{bomb-unshaded.png => bomb_unshaded.png} (100%)
diff --git a/Content.Client/Delivery/DeliveryVisualizerSystem.cs b/Content.Client/Delivery/DeliveryVisualizerSystem.cs
index bf4a8f066b..68149e248d 100644
--- a/Content.Client/Delivery/DeliveryVisualizerSystem.cs
+++ b/Content.Client/Delivery/DeliveryVisualizerSystem.cs
@@ -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
index 0000000000..a51bb839ee
--- /dev/null
+++ b/Content.Shared/Delivery/DeliveryBombComponent.cs
@@ -0,0 +1,65 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
+namespace Content.Shared.Delivery;
+
+///
+/// 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.
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
+[Access(typeof(DeliveryModifierSystem))]
+public sealed partial class DeliveryBombComponent : Component
+{
+ ///
+ /// How often will this bomb retry to explode.
+ ///
+ [DataField]
+ public TimeSpan ExplosionRetryDelay = TimeSpan.FromSeconds(5);
+
+ ///
+ /// The time at which the next retry will happen
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField, AutoPausedField]
+ public TimeSpan NextExplosionRetry;
+
+ ///
+ /// The chance this bomb explodes each time it attempts to do so.
+ ///
+ [DataField, AutoNetworkedField]
+ public float ExplosionChance = 0.01f;
+
+ ///
+ /// How much should the chance of explosion increase each failed retry?
+ ///
+ [DataField]
+ public float ExplosionChanceRetryIncrease = 0.01f;
+
+ ///
+ /// Should this bomb get primed when the delivery is unlocked?
+ ///
+ [DataField]
+ public bool PrimeOnUnlock = true;
+
+ ///
+ /// Should this bomb get primed when the delivery is broken?
+ /// Requires to be fragile as well.
+ ///
+ [DataField]
+ public bool PrimeOnBreakage = true;
+
+ ///
+ /// Should this bomb get primed when the delivery expires?
+ /// Requires to be priority as well.
+ ///
+ [DataField]
+ public bool PrimeOnExpire = true;
+
+ ///
+ /// Multiplier to choose when a crazy person actually opens it.
+ /// Multiplicative, not additive.
+ ///
+ [DataField]
+ public float SpesoMultiplier = 1.5f;
+}
diff --git a/Content.Shared/Delivery/DeliveryModifierSystem.cs b/Content.Shared/Delivery/DeliveryModifierSystem.cs
index 2b071b18cf..0e3f620f26 100644
--- a/Content.Shared/Delivery/DeliveryModifierSystem.cs
+++ b/Content.Shared/Delivery/DeliveryModifierSystem.cs
@@ -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(OnFragileBreakage);
SubscribeLocalEvent(OnFragileExamine);
SubscribeLocalEvent(OnGetFragileMultiplier);
+
+ SubscribeLocalEvent(OnExplosiveStartup);
+ SubscribeLocalEvent(OnPrimedExplosiveMapInit);
+ SubscribeLocalEvent(OnExplosiveExamine);
+ SubscribeLocalEvent(OnGetExplosiveMultiplier);
+ SubscribeLocalEvent(OnExplosiveUnlock);
+ SubscribeLocalEvent(OnExplosiveExpire);
+ SubscribeLocalEvent(OnExplosiveBreak);
}
#region Random
@@ -119,12 +134,80 @@ public sealed partial class DeliveryModifierSystem : EntitySystem
}
#endregion
+ #region Explosive
+ private void OnExplosiveStartup(Entity ent, ref ComponentStartup args)
+ {
+ _delivery.UpdateBombVisuals(ent);
+ }
+
+ private void OnPrimedExplosiveMapInit(Entity ent, ref MapInitEvent args)
+ {
+ if (!TryComp(ent, out var bomb))
+ return;
+
+ bomb.NextExplosionRetry = _timing.CurTime;
+ }
+
+ private void OnExplosiveExamine(Entity ent, ref ExaminedEvent args)
+ {
+ var trueName = _nameModifier.GetBaseName(ent.Owner);
+
+ var isPrimed = HasComp(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 ent, ref GetDeliveryMultiplierEvent args)
+ {
+ // Big danger for big rewards
+ args.MultiplicativeMultiplier += ent.Comp.SpesoMultiplier;
+ }
+
+ private void OnExplosiveUnlock(Entity ent, ref DeliveryUnlockedEvent args)
+ {
+ if (!ent.Comp.PrimeOnUnlock)
+ return;
+
+ PrimeBombDelivery(ent);
+ }
+
+ private void OnExplosiveExpire(Entity ent, ref DeliveryPriorityExpiredEvent args)
+ {
+ if (!ent.Comp.PrimeOnExpire)
+ return;
+
+ PrimeBombDelivery(ent);
+ }
+
+ private void OnExplosiveBreak(Entity ent, ref BreakageEventArgs args)
+ {
+ if (!ent.Comp.PrimeOnBreakage)
+ return;
+
+ PrimeBombDelivery(ent);
+ }
+
+ [PublicAPI]
+ public void PrimeBombDelivery(Entity ent)
+ {
+ EnsureComp(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();
+ 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
}
diff --git a/Content.Shared/Delivery/DeliveryVisuals.cs b/Content.Shared/Delivery/DeliveryVisuals.cs
index 35391854be..b63d6a20bb 100644
--- a/Content.Shared/Delivery/DeliveryVisuals.cs
+++ b/Content.Shared/Delivery/DeliveryVisuals.cs
@@ -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
index 0000000000..f3fd124f28
--- /dev/null
+++ b/Content.Shared/Delivery/PrimedDeliveryBombComponent.cs
@@ -0,0 +1,11 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Delivery;
+
+///
+/// Component given to deliveries.
+/// Indicates this bomb delivery is primed.
+///
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(DeliveryModifierSystem))]
+public sealed partial class PrimedDeliveryBombComponent : Component;
diff --git a/Content.Shared/Delivery/SharedDeliverySystem.cs b/Content.Shared/Delivery/SharedDeliverySystem.cs
index 175dfbe70d..52f83500e1 100644
--- a/Content.Shared/Delivery/SharedDeliverySystem.cs
+++ b/Content.Shared/Delivery/SharedDeliverySystem.cs
@@ -259,6 +259,13 @@ public abstract class SharedDeliverySystem : EntitySystem
_appearance.SetData(ent, DeliveryVisuals.IsFragile, isFragile);
}
+ public void UpdateBombVisuals(Entity ent)
+ {
+ var isPrimed = HasComp(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);
diff --git a/Resources/Locale/en-US/delivery/delivery-component.ftl b/Resources/Locale/en-US/delivery/delivery-component.ftl
index c346b2a813..306dd9b044 100644
--- a/Resources/Locale/en-US/delivery/delivery-component.ftl
+++ b/Resources/Locale/en-US/delivery/delivery-component.ftl
@@ -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.
diff --git a/Resources/Prototypes/Entities/Objects/Deliveries/deliveries.yml b/Resources/Prototypes/Entities/Objects/Deliveries/deliveries.yml
index a209f5c6f7..acf88fc8b3 100644
--- a/Resources/Prototypes/Entities/Objects/Deliveries/deliveries.yml
+++ b/Resources/Prototypes/Entities/Objects/Deliveries/deliveries.yml
@@ -27,6 +27,15 @@
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
@@ -74,6 +83,13 @@
- 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
@@ -117,6 +133,13 @@
- 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
@@ -139,6 +162,8 @@
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
@@ -177,3 +202,21 @@
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
diff --git a/Resources/Textures/Objects/Specific/Cargo/mail.rsi/bomb-unshaded.png b/Resources/Textures/Objects/Specific/Cargo/mail.rsi/bomb_unshaded.png
similarity index 100%
rename from Resources/Textures/Objects/Specific/Cargo/mail.rsi/bomb-unshaded.png
rename to Resources/Textures/Objects/Specific/Cargo/mail.rsi/bomb_unshaded.png
diff --git a/Resources/Textures/Objects/Specific/Cargo/mail.rsi/meta.json b/Resources/Textures/Objects/Specific/Cargo/mail.rsi/meta.json
index 9aa97992b1..500d1632fc 100644
--- a/Resources/Textures/Objects/Specific/Cargo/mail.rsi/meta.json
+++ b/Resources/Textures/Objects/Specific/Cargo/mail.rsi/meta.json
@@ -43,7 +43,7 @@
"name": "bomb"
},
{
- "name": "bomb-unshaded",
+ "name": "bomb_unshaded",
"delays": [
[
0.2,
diff --git a/Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/bomb-unshaded.png b/Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/bomb_unshaded.png
similarity index 100%
rename from Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/bomb-unshaded.png
rename to Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/bomb_unshaded.png
diff --git a/Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/meta.json b/Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/meta.json
index a265c4aada..67fafe31b3 100644
--- a/Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/meta.json
+++ b/Resources/Textures/Objects/Specific/Cargo/mail_large.rsi/meta.json
@@ -43,7 +43,7 @@
"name": "bomb"
},
{
- "name": "bomb-unshaded",
+ "name": "bomb_unshaded",
"delays": [
[
0.125,