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.Chat;
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;
///
/// System for managing deliveries spawned by the mail teleporter.
/// This covers for mail spawning, as well as granting cargo money.
///
public sealed partial class DeliverySystem : SharedDeliverySystem
{
[Dependency] private readonly CargoSystem _cargo = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StationRecordsSystem _records = default!;
[Dependency] private readonly StationSystem _station = default!;
[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!;
///
/// Default reason to use if the penalization is triggered
///
private static readonly LocId DefaultMessage = "delivery-penalty-default-reason";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent(OnMapInit);
InitializeSpawning();
}
private void OnMapInit(Entity ent, ref MapInitEvent args)
{
_container.EnsureContainer(ent, ent.Comp.Container);
if (_station.GetStationInMap(Transform(ent).MapID) is not { } stationId)
return;
if (!_records.TryGetRandomRecord(stationId, out var entry))
return;
ent.Comp.RecipientName = entry.Name;
ent.Comp.RecipientJobTitle = entry.JobTitle;
ent.Comp.RecipientStation = stationId;
_appearance.SetData(ent, DeliveryVisuals.JobIcon, entry.JobIcon);
_label.Label(ent, ent.Comp.RecipientName);
if (TryComp(ent, out var reader) && entry.Fingerprint != null)
{
_fingerprintReader.AddAllowedFingerprint((ent.Owner, reader), entry.Fingerprint);
}
Dirty(ent);
}
protected override void GrantSpesoReward(Entity ent)
{
if (!Resolve(ent, ref ent.Comp))
return;
if (!TryComp(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)));
}
///
/// Runs the penalty logic: Announcing the penalty and calculating how much to charge the designated account
///
/// The delivery for which to run the penalty.
/// The penalty reason, displayed in front of the message.
protected override void HandlePenalty(Entity ent, string? reason = null)
{
if (!TryComp(ent.Comp.RecipientStation, out var stationAccount))
return;
if (ent.Comp.WasPenalized)
return;
if (!_protoMan.Resolve(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, 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, 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));
}
public override void Update(float frameTime)
{
base.Update(frameTime);
UpdateSpawner(frameTime);
}
}