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;
[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()
{
{
_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);
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)
+using Content.Shared.Cargo.Prototypes;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
namespace Content.Shared.Delivery;
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.
[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>