]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Delivery system now has the possibility of penalisation (#36660)
authorJ <billsmith116@gmail.com>
Thu, 24 Apr 2025 16:05:32 +0000 (16:05 +0000)
committerGitHub <noreply@github.com>
Thu, 24 Apr 2025 16:05:32 +0000 (18:05 +0200)
* Add new fields to DeliveryComponent for #36636

* Setting the baseSpesoPenalty for currently available deliveries

* Small fixes

* Basic delivery penalization

* Penalty and reward multiplier calculation in place

Also fixes an issue in SharedCargoSystem when opening a delivery in dev server due to trying to allocate cargo twice.

* Calling penalty no longer happens on opening

* Extract multiplier getting

* Removing unused include

* Changing method description. \n\n Not actually sure what I meant by the first one

* Localising default delivery messages

* Unused include removal

* minor tweaks

* slarti changes

* forgot

* stuffs

* yippee

* Locn't

* doc

* Apply suggestions from code review

---------

Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com>
Co-authored-by: ScarKy0 <scarky0@onet.eu>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Content.Server/Delivery/DeliverySystem.cs
Content.Shared/Delivery/DeliveryComponent.cs
Content.Shared/Delivery/DeliverySpawnerComponent.cs
Content.Shared/Delivery/SharedDeliverySystem.cs
Resources/Locale/en-US/delivery/delivery-messages.ftl [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Deliveries/deliveries.yml

index 329e3d11edf47c810020ffa1666cb8ae2f12ec05..0ddfde49ae9405730848e712a4a304550c246fe9 100644 (file)
@@ -1,13 +1,16 @@
 using Content.Server.Cargo.Systems;
+using Content.Server.Chat.Systems;
 using Content.Server.Station.Systems;
 using Content.Server.StationRecords.Systems;
 using Content.Shared.Cargo.Components;
+using Content.Shared.Cargo.Prototypes;
 using Content.Shared.Delivery;
 using Content.Shared.FingerprintReader;
 using Content.Shared.Labels.EntitySystems;
 using Content.Shared.StationRecords;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Containers;
+using Robust.Shared.Prototypes;
 
 namespace Content.Server.Delivery;
 
@@ -25,6 +28,13 @@ public sealed partial class DeliverySystem : SharedDeliverySystem
     [Dependency] private readonly FingerprintReaderSystem _fingerprintReader = default!;
     [Dependency] private readonly LabelSystem _label = default!;
     [Dependency] private readonly SharedContainerSystem _container = default!;
+    [Dependency] private readonly ChatSystem _chat = default!;
+    [Dependency] private readonly IPrototypeManager _protoMan = default!;
+
+    /// <summary>
+    /// Default reason to use if the penalization is triggered
+    /// </summary>
+    private static readonly LocId DefaultMessage = "delivery-penalty-default-reason";
 
     public override void Initialize()
     {
@@ -39,19 +49,15 @@ public sealed partial class DeliverySystem : SharedDeliverySystem
     {
         _container.EnsureContainer<Container>(ent, ent.Comp.Container);
 
-        var stationId = _station.GetStationInMap(Transform(ent).MapID);
-
-        if (stationId == null)
+        if (_station.GetStationInMap(Transform(ent).MapID) is not { } stationId)
             return;
 
-        _records.TryGetRandomRecord<GeneralStationRecord>(stationId.Value, out var entry);
-
-        if (entry == null)
+        if (!_records.TryGetRandomRecord<GeneralStationRecord>(stationId, out var entry))
             return;
 
         ent.Comp.RecipientName = entry.Name;
         ent.Comp.RecipientJobTitle = entry.JobTitle;
-        ent.Comp.RecipientStation = stationId.Value;
+        ent.Comp.RecipientStation = stationId;
 
         _appearance.SetData(ent, DeliveryVisuals.JobIcon, entry.JobIcon);
 
@@ -73,10 +79,74 @@ public sealed partial class DeliverySystem : SharedDeliverySystem
         if (!TryComp<StationBankAccountComponent>(ent.Comp.RecipientStation, out var account))
             return;
 
+        var stationAccountEnt = (ent.Comp.RecipientStation.Value, account);
+
+        var multiplier = GetDeliveryMultiplier(ent!); // Resolve so we know it's got the component
+
+        _cargo.UpdateBankAccount(
+            stationAccountEnt,
+            (int)(ent.Comp.BaseSpesoReward * multiplier),
+           _cargo.CreateAccountDistribution((ent.Comp.RecipientStation.Value, account)));
+    }
+
+    /// <summary>
+    /// Runs the penalty logic: Announcing the penalty and calculating how much to charge the designated account
+    /// </summary>
+    /// <param name="ent">The delivery for which to run the penalty.</param>
+    /// <param name="reason">The penalty reason, displayed in front of the message.</param>
+    protected override void HandlePenalty(Entity<DeliveryComponent> ent, string? reason = null)
+    {
+        if (!TryComp<StationBankAccountComponent>(ent.Comp.RecipientStation, out var stationAccount))
+            return;
+
+        if (ent.Comp.WasPenalized)
+            return;
+
+        if (!_protoMan.TryIndex(ent.Comp.PenaltyBankAccount, out var accountInfo))
+            return;
+
+        var multiplier = GetDeliveryMultiplier(ent);
+
+        var localizedAccountName = Loc.GetString(accountInfo.Name);
+
+        reason ??= Loc.GetString(DefaultMessage);
+
+        var dist = new Dictionary<ProtoId<CargoAccountPrototype>, double>()
+        {
+            { ent.Comp.PenaltyBankAccount, 1.0 }
+        };
+
+        var penaltyAccountBalance = stationAccount.Accounts[ent.Comp.PenaltyBankAccount];
+        var calculatedPenalty = (int)(ent.Comp.BaseSpesoPenalty * multiplier);
+
+        // Prevents cargo from going into negatives
+        if (calculatedPenalty > penaltyAccountBalance )
+            calculatedPenalty = Math.Max(0, penaltyAccountBalance);
+
         _cargo.UpdateBankAccount(
-            (ent.Comp.RecipientStation.Value, account),
-            ent.Comp.SpesoReward,
-            _cargo.CreateAccountDistribution((ent.Comp.RecipientStation.Value, account)));
+            (ent.Comp.RecipientStation.Value, stationAccount),
+            -calculatedPenalty,
+            dist);
+
+        var message = Loc.GetString("delivery-penalty-message", ("reason", reason), ("spesos", calculatedPenalty), ("account", localizedAccountName.ToUpper()));
+        _chat.TrySendInGameICMessage(ent, message, InGameICChatType.Speak, hideChat: true);
+
+        ent.Comp.WasPenalized = true;
+        DirtyField(ent.Owner, ent.Comp, nameof(DeliveryComponent.WasPenalized));
+    }
+
+    /// <summary>
+    /// Gathers the total multiplier for a delivery.
+    /// This is done by components having subscribed to GetDeliveryMultiplierEvent and having added onto it.
+    /// </summary>
+    /// <param name="ent">The delivery for which to get the multiplier.</param>
+    /// <returns>Total multiplier.</returns>
+    private float GetDeliveryMultiplier(Entity<DeliveryComponent> ent)
+    {
+        var ev = new GetDeliveryMultiplierEvent();
+        RaiseLocalEvent(ent, ref ev);
+
+        return ev.Multiplier;
     }
 
     public override void Update(float frameTime)
index 19effcd211a2acfd0f9213cde3d198c2cfef57c9..3eabb5165ccd46db1ffe1dc7e6878d999b0873be 100644 (file)
@@ -1,5 +1,7 @@
+using Content.Shared.Cargo.Prototypes;
 using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Delivery;
 
@@ -23,10 +25,16 @@ public sealed partial class DeliveryComponent : Component
     public bool IsLocked = true;
 
     /// <summary>
-    /// The amount of spesos that gets added to the station bank account on unlock.
+    /// The base amount of spesos that gets added to the station bank account on unlock.
     /// </summary>
     [DataField, AutoNetworkedField]
-    public int SpesoReward = 500;
+    public int BaseSpesoReward = 500;
+
+    /// <summary>
+    /// The base amount of spesos that will be removed from the station bank account on a penalized delivery
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public int BaseSpesoPenalty = 250;
 
     /// <summary>
     /// The name of the recipient of this delivery.
@@ -48,6 +56,19 @@ public sealed partial class DeliveryComponent : Component
     [DataField, AutoNetworkedField]
     public EntityUid? RecipientStation;
 
+    /// <summary>
+    /// The bank account ID of the account to subtract funds from in case of penalization
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public ProtoId<CargoAccountPrototype> PenaltyBankAccount = "Cargo";
+
+    /// <summary>
+    /// Whether this delivery has already received a penalty.
+    /// Used to avoid getting penalized several times.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public bool WasPenalized;
+
     /// <summary>
     /// The sound to play when the delivery is unlocked.
     /// </summary>
index 9ed3ff1b915cc2718b1d563e193b1f7cc5beae89..81e8c97cf5275f64223c7f3fc2a8b7c463914d48 100644 (file)
@@ -1,8 +1,6 @@
 using Content.Shared.EntityTable.EntitySelectors;
 using Robust.Shared.Audio;
 using Robust.Shared.GameStates;
-using Robust.Shared.Prototypes;
-
 namespace Content.Shared.Delivery;
 
 /// <summary>
index 8d343b4acbbfe1f5239b6be018c87adecbbb9191..ffbf520610c4b97b2207277c99711e38c01ddcc5 100644 (file)
@@ -210,9 +210,21 @@ public abstract class SharedDeliverySystem : EntitySystem
 
     protected virtual void GrantSpesoReward(Entity<DeliveryComponent?> ent) { }
 
+    protected virtual void HandlePenalty(Entity<DeliveryComponent> ent, string? reason = null) { }
+
     protected virtual void SpawnDeliveries(Entity<DeliverySpawnerComponent?> ent) { }
 }
 
+/// <summary>
+/// Used to gather the multiplier from all different delivery components.
+/// </summary>
+[ByRefEvent]
+public record struct GetDeliveryMultiplierEvent(float Multiplier)
+{
+    // we can't use an optional parameter because the default parameterless constructor defaults everything
+    public GetDeliveryMultiplierEvent() : this(1.0f) { }
+}
+
 /// <summary>
 /// Event raised on the delivery when it is unlocked.
 /// </summary>
diff --git a/Resources/Locale/en-US/delivery/delivery-messages.ftl b/Resources/Locale/en-US/delivery/delivery-messages.ftl
new file mode 100644 (file)
index 0000000..50248e5
--- /dev/null
@@ -0,0 +1,4 @@
+delivery-penalty-default-reason = WARNING
+delivery-penalty-default-account-name = UNKNOWN ACCOUNT
+
+delivery-penalty-message = {$reason}! INVOKING A PENALTY OF {$spesos} SPESOS ON {$account}!
index 2706cf380c81e4b4cf34d73937840b864ba14506..b396b20a464174c653db7b032ba8ef3004fd77d1 100644 (file)
   - type: Item
     size: Huge
   - type: Delivery
-    spesoReward: 1000
+    baseSpesoReward: 1000
+    baseSpesoPenalty: 500
+  - type: Speech
+    speechVerb: Robotic
   - type: EntityTableContainerFill
     containers:
       delivery: !type:NestedSelector
   - type: Item
     storedRotation: 90
   - type: Delivery
-    spesoReward: 500
+    baseSpesoReward: 500
+    baseSpesoPenalty: 250
+  - type: Speech
+    speechVerb: Robotic
   - type: EntityTableContainerFill
     containers:
       delivery: !type:NestedSelector