]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Reworked Mail Spawning (#36774)
authorScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Mon, 21 Apr 2025 09:32:18 +0000 (11:32 +0200)
committerGitHub <noreply@github.com>
Mon, 21 Apr 2025 09:32:18 +0000 (11:32 +0200)
* init

* stuff

Content.Client/Delivery/DeliveryVisualizerSystem.cs
Content.Server/Delivery/DeliverySystem.Spawning.cs
Content.Shared/Delivery/DeliverySpawnerComponent.cs
Content.Shared/Delivery/DeliveryVisuals.cs
Content.Shared/Delivery/SharedDeliverySystem.cs
Resources/Locale/en-US/delivery/delivery-component.ftl
Resources/Prototypes/Entities/Structures/Machines/mail_teleporter.yml
Resources/Textures/Structures/mailbox.rsi/contents.png [new file with mode: 0644]
Resources/Textures/Structures/mailbox.rsi/meta.json

index 8ed15344a4307bdb50100c7e3b5e4743a24cd3a2..bf4a8f066b4d7dc97619f6d67a8fcba3f018a535 100644 (file)
@@ -43,3 +43,9 @@ public enum DeliveryVisualLayers : byte
     Breakage,
     Trash,
 }
+
+public enum DeliverySpawnerVisualLayers : byte
+{
+    Contents,
+}
+
index 19087e74487a77282823dbd64b04f3c73d97ebb3..a7496a343b04be1d4d3f2571176b6ae12c00a340 100644 (file)
@@ -1,6 +1,6 @@
-using Content.Server.Power.EntitySystems;
-using Content.Server.StationRecords;
 using Content.Shared.Delivery;
+using Content.Shared.Power.EntitySystems;
+using Content.Server.StationRecords;
 using Content.Shared.EntityTable;
 using Robust.Shared.Random;
 using Robust.Shared.Timing;
@@ -16,7 +16,7 @@ public sealed partial class DeliverySystem
     [Dependency] private readonly IGameTiming _timing = default!;
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly EntityTableSystem _entityTable = default!;
-    [Dependency] private readonly PowerReceiverSystem _power = default!;
+    [Dependency] private readonly SharedPowerReceiverSystem _power = default!;
 
     private void InitializeSpawning()
     {
@@ -28,16 +28,14 @@ public sealed partial class DeliverySystem
         ent.Comp.NextDelivery = _timing.CurTime + ent.Comp.MinDeliveryCooldown; // We want an early wave of mail so cargo doesn't have to wait
     }
 
-    private void SpawnDelivery(Entity<DeliverySpawnerComponent?> ent, int amount)
+    protected override void SpawnDeliveries(Entity<DeliverySpawnerComponent?> ent)
     {
         if (!Resolve(ent.Owner, ref ent.Comp))
             return;
 
         var coords = Transform(ent).Coordinates;
 
-        _audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
-
-        for (int i = 0; i < amount; i++)
+        for (int i = 0; i < ent.Comp.ContainedDeliveryAmount; i++)
         {
             var spawns = _entityTable.GetSpawns(ent.Comp.Table);
 
@@ -46,9 +44,12 @@ public sealed partial class DeliverySystem
                 Spawn(id, coords);
             }
         }
+
+        ent.Comp.ContainedDeliveryAmount = 0;
+        Dirty(ent);
     }
 
-    private void SpawnStationDeliveries(Entity<CargoDeliveryDataComponent> ent)
+    private void AdjustStationDeliveries(Entity<CargoDeliveryDataComponent> ent)
     {
         if (!TryComp<StationRecordsComponent>(ent, out var records))
             return;
@@ -72,7 +73,7 @@ public sealed partial class DeliverySystem
         {
             foreach (var spawner in spawners)
             {
-                SpawnDelivery(spawner, deliveryCount);
+                AddDeliveriesToSpawner(spawner, deliveryCount);
             }
         }
         else
@@ -87,18 +88,18 @@ public sealed partial class DeliverySystem
             }
             for (int j = 0; j < spawners.Count; j++)
             {
-                SpawnDelivery(spawners[j], amounts[j]);
+                AddDeliveriesToSpawner(spawners[j], amounts[j]);
             }
         }
 
     }
 
-    private List<EntityUid> GetValidSpawners(Entity<CargoDeliveryDataComponent> ent)
+    private List<Entity<DeliverySpawnerComponent>> GetValidSpawners(Entity<CargoDeliveryDataComponent> ent)
     {
-        var validSpawners = new List<EntityUid>();
+        var validSpawners = new List<Entity<DeliverySpawnerComponent>>();
 
         var spawners = EntityQueryEnumerator<DeliverySpawnerComponent>();
-        while (spawners.MoveNext(out var spawnerUid, out _))
+        while (spawners.MoveNext(out var spawnerUid, out var spawnerComp))
         {
             var spawnerStation = _station.GetOwningStation(spawnerUid);
 
@@ -108,12 +109,23 @@ public sealed partial class DeliverySystem
             if (!_power.IsPowered(spawnerUid))
                 continue;
 
-            validSpawners.Add(spawnerUid);
+            if (spawnerComp.ContainedDeliveryAmount >= spawnerComp.MaxContainedDeliveryAmount)
+                continue;
+
+            validSpawners.Add((spawnerUid, spawnerComp));
         }
 
         return validSpawners;
     }
 
+    private void AddDeliveriesToSpawner(Entity<DeliverySpawnerComponent> ent, int amount)
+    {
+        ent.Comp.ContainedDeliveryAmount += Math.Clamp(amount, 0, ent.Comp.MaxContainedDeliveryAmount - ent.Comp.ContainedDeliveryAmount);
+        _audio.PlayPvs(ent.Comp.SpawnSound, ent.Owner);
+        UpdateDeliverySpawnerVisuals(ent, ent.Comp.ContainedDeliveryAmount);
+        Dirty(ent);
+    }
+
     private void UpdateSpawner(float frameTime)
     {
         var dataQuery = EntityQueryEnumerator<CargoDeliveryDataComponent>();
@@ -125,7 +137,7 @@ public sealed partial class DeliverySystem
                 continue;
 
             deliveryData.NextDelivery += _random.Next(deliveryData.MinDeliveryCooldown, deliveryData.MaxDeliveryCooldown); // Random cooldown between min and max
-            SpawnStationDeliveries((uid, deliveryData));
+            AdjustStationDeliveries((uid, deliveryData));
         }
     }
 }
index 4491509cb3585efef16ddb2d8ec0a211393c1653..9ed3ff1b915cc2718b1d563e193b1f7cc5beae89 100644 (file)
@@ -9,7 +9,7 @@ namespace Content.Shared.Delivery;
 /// Used to mark entities that are valid for spawning deliveries on.
 /// If this requires power, it needs to be powered to count as a valid spawner.
 /// </summary>
-[RegisterComponent, NetworkedComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
 public sealed partial class DeliverySpawnerComponent : Component
 {
     /// <summary>
@@ -18,9 +18,28 @@ public sealed partial class DeliverySpawnerComponent : Component
     [DataField(required: true)]
     public EntityTableSelector Table = default!;
 
+    /// <summary>
+    /// The max amount of deliveries this spawner can hold at a time.
+    /// </summary>
+    [DataField]
+    public int MaxContainedDeliveryAmount = 20;
+
+    /// <summary>
+    /// The currently held amount of deliveries.
+    /// They are stored as an int and only spawned on use, as to not create additional entities without the need to.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public int ContainedDeliveryAmount;
+
     /// <summary>
     /// The sound to play when the spawner spawns a delivery.
     /// </summary>
     [DataField]
     public SoundSpecifier? SpawnSound = new SoundCollectionSpecifier("DeliverySpawnSounds", AudioParams.Default.WithVolume(-7));
+
+    /// <summary>
+    /// The sound to play when a spawner is opened, and spills all the deliveries out.
+    /// </summary>
+    [DataField]
+    public SoundSpecifier? OpenSound = new SoundCollectionSpecifier("storageRustle");
 }
index 6da45b62774de6a1982ccf510022d40685f1e30b..69eb5fda9ea1339f2febcd13c8a8fc554d87fcd5 100644 (file)
@@ -13,3 +13,9 @@ public enum DeliveryVisuals : byte
     IsPriorityInactive,
     JobIcon,
 }
+
+[Serializable, NetSerializable]
+public enum DeliverySpawnerVisuals : byte
+{
+    Contents,
+}
index 319bf41fce4d7d63ce649fd48259a3707fc74fe3..8d343b4acbbfe1f5239b6be018c87adecbbb9191 100644 (file)
@@ -38,12 +38,15 @@ public abstract class SharedDeliverySystem : EntitySystem
     {
         base.Initialize();
 
-        SubscribeLocalEvent<DeliveryComponent, ExaminedEvent>(OnExamine);
+        SubscribeLocalEvent<DeliveryComponent, ExaminedEvent>(OnDeliveryExamine);
         SubscribeLocalEvent<DeliveryComponent, UseInHandEvent>(OnUseInHand);
-        SubscribeLocalEvent<DeliveryComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
+        SubscribeLocalEvent<DeliveryComponent, GetVerbsEvent<AlternativeVerb>>(OnGetDeliveryVerbs);
+
+        SubscribeLocalEvent<DeliverySpawnerComponent, ExaminedEvent>(OnSpawnerExamine);
+        SubscribeLocalEvent<DeliverySpawnerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetSpawnerVerbs);
     }
 
-    private void OnExamine(Entity<DeliveryComponent> ent, ref ExaminedEvent args)
+    private void OnDeliveryExamine(Entity<DeliveryComponent> ent, ref ExaminedEvent args)
     {
         var jobTitle = ent.Comp.RecipientJobTitle ?? Loc.GetString("delivery-recipient-no-job");
         var recipientName = ent.Comp.RecipientName ?? Loc.GetString("delivery-recipient-no-name");
@@ -56,6 +59,11 @@ public abstract class SharedDeliverySystem : EntitySystem
         args.PushText(Loc.GetString("delivery-recipient-examine", ("recipient", recipientName), ("job", jobTitle)));
     }
 
+    private void OnSpawnerExamine(Entity<DeliverySpawnerComponent> ent, ref ExaminedEvent args)
+    {
+        args.PushMarkup(Loc.GetString("delivery-teleporter-amount-examine", ("amount", ent.Comp.ContainedDeliveryAmount)), 50);
+    }
+
     private void OnUseInHand(Entity<DeliveryComponent> ent, ref UseInHandEvent args)
     {
         args.Handled = true;
@@ -69,7 +77,7 @@ public abstract class SharedDeliverySystem : EntitySystem
             OpenDelivery(ent, args.User);
     }
 
-    private void OnGetVerbs(Entity<DeliveryComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
+    private void OnGetDeliveryVerbs(Entity<DeliveryComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
     {
         if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.IsOpened)
             return;
@@ -92,6 +100,33 @@ public abstract class SharedDeliverySystem : EntitySystem
         });
     }
 
+    private void OnGetSpawnerVerbs(Entity<DeliverySpawnerComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
+    {
+        if (!args.CanAccess || !args.CanInteract || args.Hands == null)
+            return;
+
+        var user = args.User;
+
+        args.Verbs.Add(new AlternativeVerb()
+        {
+            Act = () =>
+            {
+                _audio.PlayPredicted(ent.Comp.OpenSound, ent.Owner, user);
+
+                if(ent.Comp.ContainedDeliveryAmount == 0)
+                {
+                    _popup.PopupPredicted(Loc.GetString("delivery-teleporter-empty", ("entity", ent)), null, ent, user);
+                    return;
+                }
+
+                SpawnDeliveries(ent.Owner);
+
+                UpdateDeliverySpawnerVisuals(ent, ent.Comp.ContainedDeliveryAmount);
+            },
+            Text = Loc.GetString("delivery-teleporter-empty-verb"),
+        });
+    }
+
     private bool TryUnlockDelivery(Entity<DeliveryComponent> ent, EntityUid user, bool rewardMoney = true)
     {
         // Check fingerprint access if there is a reader on the mail
@@ -168,7 +203,14 @@ public abstract class SharedDeliverySystem : EntitySystem
             _appearance.SetData(uid, DeliveryVisuals.IsPriority, false);
     }
 
+    protected void UpdateDeliverySpawnerVisuals(EntityUid uid, int contents)
+    {
+        _appearance.SetData(uid, DeliverySpawnerVisuals.Contents, contents > 0);
+    }
+
     protected virtual void GrantSpesoReward(Entity<DeliveryComponent?> ent) { }
+
+    protected virtual void SpawnDeliveries(Entity<DeliverySpawnerComponent?> ent) { }
 }
 
 /// <summary>
index 499b708284454311849cf9eeb1e3d6853e967ce6..fbe4e74937f3869882db6983e0f061d667196548 100644 (file)
@@ -10,3 +10,11 @@ delivery-opened-others = {CAPITALIZE($recipient)} opened the {$delivery}.
 
 delivery-unlock-verb = Unlock
 delivery-open-verb = Open
+
+delivery-teleporter-amount-examine =
+    { $amount ->
+        [one] It contains [color=yellow]{$amount}[/color] delivery.
+        *[other] It contains [color=yellow]{$amount}[/color] deliveries.
+    }
+delivery-teleporter-empty = The {$entity} is empty.
+delivery-teleporter-empty-verb = Take mail
index a03f166bbed59b977cbee67b4658ec888ddc3376..6842e3c95894569bf3c3b5751fc5263dc134522c 100644 (file)
@@ -20,6 +20,9 @@
     snapCardinals: true
     layers:
     - state: icon
+    - state: contents
+      map: [ "enum.DeliverySpawnerVisualLayers.Contents" ]
+      visible: false
     - state: unlit
       shader: unshaded
       visible: false
   - type: Appearance
   - type: GenericVisualizer
     visuals:
+      enum.DeliverySpawnerVisuals.Contents:
+        enum.DeliverySpawnerVisualLayers.Contents:
+          True: { visible: true }
+          False: { visible: false }
       enum.PowerDeviceVisuals.Powered:
         enum.PowerDeviceVisualLayers.Powered:
           True: { visible: true }
diff --git a/Resources/Textures/Structures/mailbox.rsi/contents.png b/Resources/Textures/Structures/mailbox.rsi/contents.png
new file mode 100644 (file)
index 0000000..45fab01
Binary files /dev/null and b/Resources/Textures/Structures/mailbox.rsi/contents.png differ
index ce3494c3d4bb653f9914b7f973fa366aa8ee2144..711646c2b32c81e385554363b1c6afb175208730 100644 (file)
@@ -1,7 +1,7 @@
 {
   "version": 1,
   "license": "CC-BY-SA-3.0",
-  "copyright": "Created by meijunkie on Discord, funkystation.org at commit https://github.com/funky-station/funky-station/commit/430be9247ac220367f338c2c1a716a7503b1446d",
+  "copyright": "Created by meijunkie on Discord, funkystation.org at commit https://github.com/funky-station/funky-station/commit/430be9247ac220367f338c2c1a716a7503b1446d, contents by ScarKy0 (Github)",
   "size": {
     "x": 32,
     "y": 32
@@ -12,6 +12,9 @@
     },
     {
       "name": "unlit"
+    },
+    {
+      "name": "contents"
     }
   ]
 }