Bomb Deliveries (#37069)

* init

* BOMB!!!

* review

* partial review

* review
This commit is contained in:
ScarKy0
2025-05-18 10:57:22 +02:00
committed by GitHub
parent 5b7c00b374
commit 30537e13a4
12 changed files with 246 additions and 2 deletions

View File

@@ -42,6 +42,8 @@ public enum DeliveryVisualLayers : byte
PriorityTape,
Breakage,
Trash,
Bomb,
BombPrimed,
}
public enum DeliverySpawnerVisualLayers : byte

View File

@@ -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;
}

View 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
}

View 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
{

View File

@@ -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;

View 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);

View 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.

View File

@@ -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

View File

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -43,7 +43,7 @@
"name": "bomb"
},
{
"name": "bomb-unshaded",
"name": "bomb_unshaded",
"delays": [
[
0.2,

View File

@@ -43,7 +43,7 @@
"name": "bomb"
},
{
"name": "bomb-unshaded",
"name": "bomb_unshaded",
"delays": [
[
0.125,