diff --git a/Content.Client/Bank/BUI/StationBankATMMenuBoundUserInterface.cs b/Content.Client/Bank/BUI/StationBankATMMenuBoundUserInterface.cs
index f3d27247bac..028e5db36e6 100644
--- a/Content.Client/Bank/BUI/StationBankATMMenuBoundUserInterface.cs
+++ b/Content.Client/Bank/BUI/StationBankATMMenuBoundUserInterface.cs
@@ -18,6 +18,7 @@ protected override void Open()
_menu = new StationBankATMMenu();
_menu.WithdrawRequest += OnWithdraw;
+ _menu.DepositRequest += OnDeposit;
_menu.OnClose += Close;
_menu.PopulateReasons();
_menu.OpenCentered();
@@ -40,6 +41,14 @@ private void OnWithdraw()
SendMessage(new StationBankWithdrawMessage(amount, _menu.Reason, _menu.Description));
}
+ private void OnDeposit()
+ {
+ if (_menu?.Amount is not int amount)
+ return;
+
+ SendMessage(new StationBankDepositMessage(amount, _menu.Reason, _menu.Description));
+ }
+
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
@@ -49,5 +58,6 @@ protected override void UpdateState(BoundUserInterfaceState state)
_menu?.SetEnabled(bankState.Enabled);
_menu?.SetBalance(bankState.Balance);
+ _menu?.SetDeposit(bankState.Deposit);
}
}
diff --git a/Content.Client/Bank/UI/StationBankATMMenu.xaml b/Content.Client/Bank/UI/StationBankATMMenu.xaml
index 0e30c64d84b..60f1fe06954 100644
--- a/Content.Client/Bank/UI/StationBankATMMenu.xaml
+++ b/Content.Client/Bank/UI/StationBankATMMenu.xaml
@@ -1,8 +1,8 @@
+ SetSize="480 230"
+ MinSize="360 230">
-
+
+
+
+
+
+
+
diff --git a/Content.Client/Bank/UI/StationBankATMMenu.xaml.cs b/Content.Client/Bank/UI/StationBankATMMenu.xaml.cs
index e5efdb7dd63..0ddd66325a6 100644
--- a/Content.Client/Bank/UI/StationBankATMMenu.xaml.cs
+++ b/Content.Client/Bank/UI/StationBankATMMenu.xaml.cs
@@ -9,6 +9,7 @@ namespace Content.Client.Bank.UI;
public sealed partial class StationBankATMMenu : FancyWindow
{
public Action? WithdrawRequest;
+ public Action? DepositRequest;
public int Amount;
private readonly List _reasonStrings = new();
public string? Reason;
@@ -17,10 +18,11 @@ public StationBankATMMenu()
{
RobustXamlLoader.Load(this);
WithdrawButton.OnPressed += OnWithdrawPressed;
+ DepositButton.OnPressed += OnDepositPressed;
Title = Loc.GetString("station-bank-atm-menu-title");
WithdrawEdit.OnTextChanged += OnAmountChanged;
Reasons.OnItemSelected += OnReasonSelected;
- WithdrawDescription.OnTextChanged += OnDescChanged;
+ AmountDescription.OnTextChanged += OnDescChanged;
}
private void SetReasonText(int id)
@@ -37,9 +39,16 @@ public void SetBalance(int amount)
BalanceLabel.Text = Loc.GetString("cargo-console-menu-points-amount", ("amount", amount.ToString()));
}
+ public void SetDeposit(int amount)
+ {
+ DepositButton.Disabled = amount <= 0;
+ DepositLabel.Text = Loc.GetString("cargo-console-menu-points-amount", ("amount", amount.ToString()));
+ }
+
public void SetEnabled(bool enabled)
{
WithdrawButton.Disabled = !enabled;
+ DepositButton.Disabled = !enabled;
}
private void OnWithdrawPressed(BaseButton.ButtonEventArgs obj)
@@ -47,6 +56,11 @@ private void OnWithdrawPressed(BaseButton.ButtonEventArgs obj)
WithdrawRequest?.Invoke();
}
+ private void OnDepositPressed(BaseButton.ButtonEventArgs obj)
+ {
+ DepositRequest?.Invoke();
+ }
+
private void OnAmountChanged(LineEdit.LineEditEventArgs args)
{
if (int.TryParse(args.Text, out var amount))
diff --git a/Content.Server/_NF/Bank/ATMSystem.cs b/Content.Server/_NF/Bank/ATMSystem.cs
index c1bc05a3826..237abfc2066 100644
--- a/Content.Server/_NF/Bank/ATMSystem.cs
+++ b/Content.Server/_NF/Bank/ATMSystem.cs
@@ -182,9 +182,9 @@ private void OnDeposit(EntityUid uid, BankATMComponent component, BankDepositMes
new BankATMMenuInterfaceState(bank.Balance, true, 0));
return;
}
+
private void OnCashSlotChanged(EntityUid uid, BankATMComponent component, ContainerModifiedMessage args)
{
-
var bankUi = _uiSystem.GetUiOrNull(uid, BankATMMenuUiKey.ATM) ?? _uiSystem.GetUiOrNull(uid, BankATMMenuUiKey.BlackMarket);
var uiUser = bankUi!.SubscribedSessions.FirstOrDefault();
diff --git a/Content.Server/_NF/Bank/BankSystem.cs b/Content.Server/_NF/Bank/BankSystem.cs
index ea8a932d371..72a7051c5e1 100644
--- a/Content.Server/_NF/Bank/BankSystem.cs
+++ b/Content.Server/_NF/Bank/BankSystem.cs
@@ -6,6 +6,7 @@
using Content.Shared.Preferences;
using Robust.Shared.GameStates;
using Robust.Shared.Network;
+using Content.Server.Cargo.Components;
namespace Content.Server.Bank;
diff --git a/Content.Server/_NF/Bank/StationATMSystem.cs b/Content.Server/_NF/Bank/StationATMSystem.cs
index e55ab593f7e..458aa80dfbe 100644
--- a/Content.Server/_NF/Bank/StationATMSystem.cs
+++ b/Content.Server/_NF/Bank/StationATMSystem.cs
@@ -9,7 +9,8 @@
using Content.Shared.Bank.BUI;
using Content.Shared.Access.Systems;
using Content.Shared.Database;
-using Robust.Server.GameObjects;
+using Robust.Shared.Containers;
+using System.Linq;
namespace Content.Server.Bank;
@@ -22,7 +23,10 @@ public sealed partial class BankSystem
private void InitializeStationATM()
{
SubscribeLocalEvent(OnWithdraw);
+ SubscribeLocalEvent(OnDeposit);
SubscribeLocalEvent(OnATMUIOpen);
+ SubscribeLocalEvent(OnCashSlotChanged);
+ SubscribeLocalEvent(OnCashSlotChanged);
}
private void OnWithdraw(EntityUid uid, StationBankATMComponent component, StationBankWithdrawMessage args)
@@ -36,6 +40,7 @@ private void OnWithdraw(EntityUid uid, StationBankATMComponent component, Statio
var station = _station.GetOwningStation(uid);
// check for a bank account
+ GetInsertedCashAmount(component, out var deposit);
if (!TryComp(station, out var stationBank))
{
@@ -43,7 +48,7 @@ private void OnWithdraw(EntityUid uid, StationBankATMComponent component, Statio
ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-no-bank"));
PlayDenySound(uid, component);
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(0, false));
+ new StationBankATMMenuInterfaceState(0, false, deposit));
return;
}
@@ -53,7 +58,7 @@ private void OnWithdraw(EntityUid uid, StationBankATMComponent component, Statio
ConsolePopup(args.Session, Loc.GetString("station-bank-unauthorized"));
PlayDenySound(uid, component);
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(stationBank.Balance, false));
+ new StationBankATMMenuInterfaceState(stationBank.Balance, false, deposit));
return;
}
@@ -62,7 +67,7 @@ private void OnWithdraw(EntityUid uid, StationBankATMComponent component, Statio
ConsolePopup(args.Session, Loc.GetString("station-bank-requires-reason"));
PlayDenySound(uid, component);
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid)));
+ new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid), deposit));
return;
}
@@ -72,7 +77,7 @@ private void OnWithdraw(EntityUid uid, StationBankATMComponent component, Statio
ConsolePopup(args.Session, Loc.GetString("bank-insufficient-funds"));
PlayDenySound(uid, component);
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid)));
+ new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid), deposit));
return;
}
@@ -87,27 +92,197 @@ private void OnWithdraw(EntityUid uid, StationBankATMComponent component, Statio
_stackSystem.Spawn(args.Amount, stackPrototype, uid.ToCoordinates());
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid)));
+ new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid), deposit));
}
+ private void OnDeposit(EntityUid uid, StationBankATMComponent component, StationBankDepositMessage args)
+ {
+ if (args.Session.AttachedEntity is not { Valid: true } player)
+ return;
+
+ // to keep the window stateful
+ var bui = _uiSystem.GetUi(component.Owner, BankATMMenuUiKey.ATM);
+ var station = _station.GetOwningStation(uid);
+ // check for a bank account
+
+ // gets the money inside a cashslot of an ATM.
+ // Dynamically knows what kind of cash to look for according to BankATMComponent
+ GetInsertedCashAmount(component, out var deposit);
+
+ if (!TryComp(station, out var stationBank))
+ {
+ _log.Info($"station {station} has no bank account");
+ ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-no-bank"));
+ PlayDenySound(uid, component);
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(0, false, deposit));
+ return;
+ }
+
+ // validating the cash slot was setup correctly in the yaml
+ if (component.CashSlot.ContainerSlot is not BaseContainer cashSlot)
+ {
+ _log.Info($"ATM has no cash slot");
+ ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-no-bank"));
+ PlayDenySound(uid, component);
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(0, false, deposit));
+ return;
+ }
+
+ if (!_access.IsAllowed(player, uid))
+ {
+ _log.Info($"{player} tried to access stationo bank account");
+ ConsolePopup(args.Session, Loc.GetString("station-bank-unauthorized"));
+ PlayDenySound(uid, component);
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(stationBank.Balance, false, deposit));
+ return;
+ }
+
+ if (args.Description == null || args.Reason == null)
+ {
+ ConsolePopup(args.Session, Loc.GetString("station-bank-requires-reason"));
+ PlayDenySound(uid, component);
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid), deposit));
+ return;
+ }
+
+ // validate stack prototypes
+ if (!TryComp(component.CashSlot.ContainerSlot.ContainedEntity, out var stackComponent) ||
+ stackComponent.StackTypeId == null)
+ {
+ _log.Info($"ATM cash slot contains bad stack prototype");
+ ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-wrong-cash"));
+ PlayDenySound(uid, component);
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(0, false, deposit));
+ return;
+ }
+
+ // and then check them against the ATM's CashType
+ if (_prototypeManager.Index(component.CashType) != _prototypeManager.Index(stackComponent.StackTypeId))
+ {
+ _log.Info($"{stackComponent.StackTypeId} is not {component.CashType}");
+ ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-wrong-cash"));
+ PlayDenySound(uid, component);
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(0, false, deposit));
+ return;
+ }
+
+ // try to deposit the inserted cash into a player's bank acount.
+ if (args.Amount <= 0)
+ {
+ _log.Info($"{args.Amount} is invalid");
+ ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-transaction-denied"));
+ PlayDenySound(uid, component);
+ return;
+ }
+
+ if (deposit < args.Amount)
+ {
+ _log.Info($"{args.Amount} is more then {deposit}");
+ ConsolePopup(args.Session, Loc.GetString("bank-insufficient-funds"));
+ PlayDenySound(uid, component);
+ return;
+ }
+
+ _cargo.DeductFunds(stationBank, -args.Amount);
+ ConsolePopup(args.Session, Loc.GetString("bank-atm-menu-deposit-successful"));
+ PlayConfirmSound(uid, component);
+ _log.Info($"{args.Session.UserId} {args.Session.Name} deposited {args.Amount}, '{args.Reason}': {args.Description}");
+
+ _adminLogger.Add(LogType.ATMUsage, LogImpact.Low, $"{ToPrettyString(player):actor} deposited {args.Amount} to station bank account. '{args.Reason}': {args.Description}");
+
+ SetInsertedCashAmount(component, args.Amount, out int leftAmount, out bool empty);
+
+ // yeet and delete the stack in the cash slot after success if its worth 0
+ if (empty)
+ _containerSystem.CleanContainer(cashSlot);
+
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid), leftAmount));
+ }
+
+ private void OnCashSlotChanged(EntityUid uid, StationBankATMComponent component, ContainerModifiedMessage args)
+ {
+ GetInsertedCashAmount(component, out var deposit);
+ var bui = _uiSystem.GetUi(component.Owner, BankATMMenuUiKey.ATM);
+ var station = _station.GetOwningStation(uid);
+
+ if (!TryComp(station, out var bank))
+ {
+ return;
+ }
+
+ if (component.CashSlot.ContainerSlot?.ContainedEntity is not { Valid: true } cash)
+ {
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(bank.Balance, true, 0));
+ }
+
+ _uiSystem.SetUiState(bui,
+ new StationBankATMMenuInterfaceState(bank.Balance, true, deposit));
+ }
private void OnATMUIOpen(EntityUid uid, StationBankATMComponent component, BoundUIOpenedEvent args)
{
if (args.Session.AttachedEntity is not { Valid : true } player)
return;
+ GetInsertedCashAmount(component, out var deposit);
var bui = _uiSystem.GetUi(component.Owner, BankATMMenuUiKey.ATM);
var station = _station.GetOwningStation(uid);
+
if (!TryComp(station, out var stationBank))
{
_log.Info($"{station} has no bank account");
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(0, false));
+ new StationBankATMMenuInterfaceState(0, false, deposit));
return;
}
_uiSystem.SetUiState(bui,
- new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid)));
+ new StationBankATMMenuInterfaceState(stationBank.Balance, _access.IsAllowed(player, uid), deposit));
+ }
+
+ private void GetInsertedCashAmount(StationBankATMComponent component, out int amount)
+ {
+ amount = 0;
+ var cashEntity = component.CashSlot.ContainerSlot?.ContainedEntity;
+
+ if (!TryComp(cashEntity, out var cashStack) ||
+ cashStack.StackTypeId != component.CashType)
+ {
+ return;
+ }
+
+ amount = cashStack.Count;
+ return;
+ }
+
+ private void SetInsertedCashAmount(StationBankATMComponent component, int amount, out int leftAmount, out bool empty)
+ {
+ leftAmount = 0;
+ empty = false;
+ var cashEntity = component.CashSlot.ContainerSlot?.ContainedEntity;
+
+ if (!TryComp(cashEntity, out var cashStack) ||
+ cashStack.StackTypeId != component.CashType)
+ {
+ return;
+ }
+
+ int newAmount = cashStack.Count;
+ cashStack.Count = newAmount - amount;
+ leftAmount = cashStack.Count;
+
+ if (cashStack.Count <= 0)
+ empty = true;
+
+ return;
}
private void PlayDenySound(EntityUid uid, StationBankATMComponent component)
diff --git a/Content.Shared/_NF/Bank/BUI/StationBankATMMenuInterfaceState.cs b/Content.Shared/_NF/Bank/BUI/StationBankATMMenuInterfaceState.cs
index c236c8ebf51..a5dde050bc7 100644
--- a/Content.Shared/_NF/Bank/BUI/StationBankATMMenuInterfaceState.cs
+++ b/Content.Shared/_NF/Bank/BUI/StationBankATMMenuInterfaceState.cs
@@ -15,9 +15,15 @@ public sealed class StationBankATMMenuInterfaceState : BoundUserInterfaceState
///
public bool Enabled;
- public StationBankATMMenuInterfaceState(int balance, bool enabled)
+ ///
+ /// how much cash is inserted
+ ///
+ public int Deposit;
+
+ public StationBankATMMenuInterfaceState(int balance, bool enabled, int deposit)
{
Balance = balance;
Enabled = enabled;
+ Deposit = deposit;
}
}
diff --git a/Content.Shared/_NF/Bank/Components/StationBankATMComponent.cs b/Content.Shared/_NF/Bank/Components/StationBankATMComponent.cs
index 6ab06b94024..28be34cb689 100644
--- a/Content.Shared/_NF/Bank/Components/StationBankATMComponent.cs
+++ b/Content.Shared/_NF/Bank/Components/StationBankATMComponent.cs
@@ -1,3 +1,4 @@
+using Content.Shared.Containers.ItemSlots;
using Content.Shared.Stacks;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
@@ -12,6 +13,11 @@ public sealed partial class StationBankATMComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("cashType", customTypeSerializer:typeof(PrototypeIdSerializer))]
public string CashType = "Credit";
+ public static string CashSlotSlotId = "station-bank-ATM-cashSlot";
+
+ [DataField("station-bank-ATM-cashSlot")]
+ public ItemSlot CashSlot = new();
+
[DataField("soundError")]
public SoundSpecifier ErrorSound =
new SoundPathSpecifier("/Audio/Effects/Cargo/buzz_sigh.ogg");
diff --git a/Content.Shared/_NF/Bank/Events/StationBankDepositMessage.cs b/Content.Shared/_NF/Bank/Events/StationBankDepositMessage.cs
new file mode 100644
index 00000000000..ddbc074449d
--- /dev/null
+++ b/Content.Shared/_NF/Bank/Events/StationBankDepositMessage.cs
@@ -0,0 +1,22 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Bank.Events;
+
+///
+/// Raised on a client bank deposit
+///
+[Serializable, NetSerializable]
+
+public sealed class StationBankDepositMessage : BoundUserInterfaceMessage
+{
+ //amount to deposit. validation is happening server side but we still need client input from a text field.
+ public int Amount;
+ public string? Reason;
+ public string? Description;
+ public StationBankDepositMessage(int amount, string? reason, string? description)
+ {
+ Amount = amount;
+ Reason = reason;
+ Description = description;
+ }
+}
diff --git a/Content.Shared/_NF/Bank/SharedBankSystem.cs b/Content.Shared/_NF/Bank/SharedBankSystem.cs
index 45679fdf821..051fe8dd3d5 100644
--- a/Content.Shared/_NF/Bank/SharedBankSystem.cs
+++ b/Content.Shared/_NF/Bank/SharedBankSystem.cs
@@ -22,6 +22,8 @@ public override void Initialize()
SubscribeLocalEvent(OnHandleState);
SubscribeLocalEvent(OnComponentInit);
SubscribeLocalEvent(OnComponentRemove);
+ SubscribeLocalEvent(OnComponentInit);
+ SubscribeLocalEvent(OnComponentRemove);
}
private void OnComponentInit(EntityUid uid, BankATMComponent component, ComponentInit args)
@@ -34,6 +36,16 @@ private void OnComponentRemove(EntityUid uid, BankATMComponent component, Compon
_itemSlotsSystem.RemoveItemSlot(uid, component.CashSlot);
}
+ private void OnComponentInit(EntityUid uid, StationBankATMComponent component, ComponentInit args)
+ {
+ _itemSlotsSystem.AddItemSlot(uid, StationBankATMComponent.CashSlotSlotId, component.CashSlot);
+ }
+
+ private void OnComponentRemove(EntityUid uid, StationBankATMComponent component, ComponentRemove args)
+ {
+ _itemSlotsSystem.RemoveItemSlot(uid, component.CashSlot);
+ }
+
private void OnHandleState(EntityUid playerUid, BankAccountComponent component, ref ComponentHandleState args)
{
if (args.Current is not BankAccountComponentState state)
diff --git a/Resources/Locale/en-US/_NF/bank/bank-ATM-component.ftl b/Resources/Locale/en-US/_NF/bank/bank-ATM-component.ftl
index 0fd54dd8f8b..478dbe63761 100644
--- a/Resources/Locale/en-US/_NF/bank/bank-ATM-component.ftl
+++ b/Resources/Locale/en-US/_NF/bank/bank-ATM-component.ftl
@@ -21,4 +21,5 @@ station-bank-supplies = Station Supplies
station-bank-bounty = Bounty
station-bank-other = Other
station-bank-required = {"("}Required{")"}
-station-bank-requires-reason = NT Requires transaction details
\ No newline at end of file
+station-bank-requires-reason = NT Requires transaction details
+station-bank-unauthorized = Unauthorized!
\ No newline at end of file
diff --git a/Resources/Prototypes/_NF/Entities/Structures/atms.yml b/Resources/Prototypes/_NF/Entities/Structures/atms.yml
index 8688dfb9291..b80411d3a01 100644
--- a/Resources/Prototypes/_NF/Entities/Structures/atms.yml
+++ b/Resources/Prototypes/_NF/Entities/Structures/atms.yml
@@ -465,6 +465,15 @@
sound:
collection: Keyboard
- type: StationBankATM
+ station-bank-ATM-cashSlot:
+ name: station-bank-ATM-cashSlot
+ insertSound: /Audio/Machines/scanning.ogg
+ ejectSound: /Audio/Machines/tray_eject.ogg
+ ejectOnBreak: true
+ swap: false
+ whitelist:
+ components:
+ - Currency
- type: ActivatableUI
key: enum.BankATMMenuUiKey.ATM
- type: UserInterface
@@ -473,6 +482,10 @@
type: StationBankATMMenuBoundUserInterface
- type: AccessReader
access: [["HeadOfPersonnel"]]
+ - type: ItemSlots
+ - type: ContainerContainer
+ containers:
+ station-bank-ATM-cashSlot: !type:ContainerSlot {}
- type: Destructible
thresholds:
- trigger: