Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ab97a11
first commit!
ThanosDeGraf Apr 24, 2026
6af9bf6
forgor one or two comments
ThanosDeGraf Apr 24, 2026
fdfba26
damn you rider
ThanosDeGraf Apr 24, 2026
cb87433
Waho! Fixed the server/client component not replicating correctly
ThanosDeGraf Apr 24, 2026
32066a9
Part of the fix, darn it rider!!
ThanosDeGraf Apr 24, 2026
3899ccd
Renamed VendingMachineBoundUserInterface.Refresh() to public override…
ThanosDeGraf Apr 25, 2026
30e0b2c
SharedCreditReceiverSystem, moving OnVendingCashMoneyAfterState there.
ThanosDeGraf Apr 25, 2026
6d12653
whoops, wrong namespace
ThanosDeGraf Apr 25, 2026
a1e0437
moved cashBalance updating from vendSys to SharedCreditReceiverSystem.cs
ThanosDeGraf Apr 25, 2026
416baa1
I'll need this later
ThanosDeGraf Apr 25, 2026
95c07cb
saving work...
ThanosDeGraf Apr 26, 2026
1bfb8d0
moving more logic...
ThanosDeGraf Apr 26, 2026
8c666a5
One fixme down
ThanosDeGraf Apr 26, 2026
c6825e0
more SharedCreditReceiverSystem.cs improvements
ThanosDeGraf Apr 26, 2026
5d7787c
biiiiig move
ThanosDeGraf Apr 26, 2026
444fcdb
raaagh
ThanosDeGraf Apr 27, 2026
a24fc04
I actually dont need a bunch of these
ThanosDeGraf Apr 27, 2026
ef0508b
empty-b-gone
ThanosDeGraf Apr 27, 2026
53e1261
fixme down
ThanosDeGraf Apr 27, 2026
e270b58
new API method that returns an int instead of a bool.
ThanosDeGraf Apr 29, 2026
cd319ce
Merge branch 'main' into CreditReceiver-Created
ThanosDeGraf Apr 29, 2026
bcc999b
fix linter errors
ThanosDeGraf Apr 29, 2026
a6ab072
Merge branch 'main' into CreditReceiver-Created
ThanosDeGraf May 13, 2026
93f69c5
Fixed yaml errors
ThanosDeGraf May 13, 2026
73b4471
Added some more comments
ThanosDeGraf May 13, 2026
70c2415
buh
ThanosDeGraf May 13, 2026
8c6418d
Merge branch 'main' into CreditReceiver-Created
ThanosDeGraf May 20, 2026
49fac4f
merged "main" into my-fuckass-branch
ThanosDeGraf May 25, 2026
6a259e9
Merge branch 'main' into CreditReceiver-Created
ThanosDeGraf Jun 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Robust.Client.UserInterface;
using Robust.Shared.Input;
using System.Linq;
using Content.Shared._Mono.Economy.Component; // Mono
using Robust.Client.GameObjects;
using Content.Shared._NF.Bank.Components; // Frontier
using Content.Shared.Containers.ItemSlots; // Frontier
Expand Down Expand Up @@ -57,10 +58,10 @@ protected override void Open()
_menu.Title = Loc.GetString("vending-machine-nf-fallback-title");
// End Frontier: no exceptions
_menu.OnItemSelected += OnItemSelected;
Refresh();
Update();
}

public void Refresh()
public override void Update()
{
var system = EntMan.System<VendingMachineSystem>();
_cachedInventory = system.GetAllInventory(Owner);
Expand All @@ -73,11 +74,12 @@ public void Refresh()
_balance = bank.Balance;
}
int? cashSlotValue = null;
if (EntMan.TryGetComponent<VendingMachineComponent>(Owner, out var vendingMachine))
if (EntMan.TryGetComponent<VendingMachineComponent>(Owner, out var vendingMachine) // Mono start - Seperation of Cash from VendingMachineComp
&& EntMan.TryGetComponent<CreditReceiverComponent>(Owner, out var creditReceiver))
{
_cashSlotBalance = vendingMachine.CashSlotBalance;
_cashSlotBalance = creditReceiver.CashSlotBalance;
_requiresCash = vendingMachine.RequiresCash; // mono
if (vendingMachine.CashSlotName != null)
if (creditReceiver.CashSlotName != null) // Mono end
cashSlotValue = _cashSlotBalance;
}
else
Expand Down
7 changes: 4 additions & 3 deletions Content.Client/VendingMachines/VendingMachineSystem.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Content.Shared._Mono.Economy.Component;
using Content.Shared.VendingMachines;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
Expand Down Expand Up @@ -26,7 +27,7 @@ private void OnVendingAfterState(EntityUid uid, VendingMachineComponent componen
{
if (_uiSystem.TryGetOpenUi<VendingMachineBoundUserInterface>(uid, VendingMachineUiKey.Key, out var bui))
{
bui.Refresh();
bui.Update();
}
}

Expand All @@ -35,15 +36,15 @@ private void OnEntityInserted(Entity<VendingMachineComponent> ent, ref EntInsert
{
if (_uiSystem.TryGetOpenUi<VendingMachineBoundUserInterface>(ent.Owner, VendingMachineUiKey.Key, out var bui))
{
bui.Refresh();
bui.Update();
}
}

private void OnEntityRemoved(Entity<VendingMachineComponent> ent, ref EntRemovedFromContainerMessage args)
{
if (_uiSystem.TryGetOpenUi<VendingMachineBoundUserInterface>(ent.Owner, VendingMachineUiKey.Key, out var bui))
{
bui.Refresh();
bui.Update();
}
}
// End Frontier
Expand Down
25 changes: 25 additions & 0 deletions Content.Client/_Mono/Economy/CreditReceiverSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Content.Shared._Mono.Economy;
using Content.Shared._Mono.Economy.Component;
using Content.Shared.VendingMachines;

namespace Content.Client._Mono.Economy;

public sealed partial class CreditReceiverSystem : SharedCreditReceiverSystem
{
[Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<CreditReceiverComponent, AfterAutoHandleStateEvent>(OnVendingCashMoneyAfterState);
}

private void OnVendingCashMoneyAfterState(EntityUid uid, CreditReceiverComponent component, ref AfterAutoHandleStateEvent args)
{
if (_uiSystem.TryGetOpenUi(uid, VendingMachineUiKey.Key, out var bui))
{
bui.Update();
}
}
}
100 changes: 35 additions & 65 deletions Content.Server/VendingMachines/VendingMachineSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,33 @@
using Content.Server.Administration.Logs; // Frontier
using Content.Shared.Database; // Frontier
using Content.Shared._NF.Bank.BUI; // Frontier
using Content.Server._NF.Contraband.Systems; // Frontier
using Content.Shared.Stacks; // Frontier
using Content.Server.Stack;
using Content.Server._Mono.VendingMachine;
using Content.Shared._Mono.Traits.Physical;
using Robust.Shared.Containers; // Frontier
using Content.Shared._Mono.Economy; // Mono - Seperation of cash payment from VendingMachineComp
using Content.Shared._Mono.Economy.Component;

namespace Content.Server.VendingMachines
{
public sealed partial class VendingMachineSystem : SharedVendingMachineSystem
{
[Dependency] private IRobustRandom _random = default!;
[Dependency] private AccessReaderSystem _accessReader = default!;
[Dependency] private AppearanceSystem _appearanceSystem = default!;
[Dependency] private PricingSystem _pricing = default!;
[Dependency] private ThrowingSystem _throwingSystem = default!;
[Dependency] private IGameTiming _timing = default!;
[Dependency] private SpeakOnUIClosedSystem _speakOnUIClosed = default!;
[Dependency] private SharedPointLightSystem _light = default!;
[Dependency] private EmagSystem _emag = default!;

[Dependency] private IPrototypeManager _prototypeManager = default!; // Frontier
[Dependency] private SharedAudioSystem _audioSystem = default!; // Frontier
[Dependency] private BankSystem _bankSystem = default!; // Frontier
[Dependency] private PopupSystem _popupSystem = default!; // Frontier
[Dependency] private IAdminLogManager _adminLogger = default!; // Frontier
[Dependency] private StackSystem _stack = default!; // Frontier
[Dependency] private VendingMachinePurchaseSystem _vendingPurchase = default!; // Mono
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly AccessReaderSystem _accessReader = default!;
[Dependency] private readonly AppearanceSystem _appearanceSystem = default!;
[Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SpeakOnUIClosedSystem _speakOnUIClosed = default!;
[Dependency] private readonly SharedPointLightSystem _light = default!;
[Dependency] private readonly EmagSystem _emag = default!;

[Dependency] private readonly IPrototypeManager _prototypeManager = default!; // Frontier
[Dependency] private readonly SharedAudioSystem _audioSystem = default!; // Frontier
[Dependency] private readonly BankSystem _bankSystem = default!; // Frontier
[Dependency] private readonly PopupSystem _popupSystem = default!; // Frontier
[Dependency] private readonly IAdminLogManager _adminLogger = default!; // Frontier
[Dependency] private readonly VendingMachinePurchaseSystem _vendingPurchase = default!; // Mono
[Dependency] private readonly SharedCreditReceiverSystem _cash = default!; // Mono - Pwease chwose two pway wiw cawsh ow cwedit
Comment thread
ThanosDeGraf marked this conversation as resolved.

private const float WallVendEjectDistanceFromWall = 1f;

Expand All @@ -71,8 +70,9 @@ public override void Initialize()
SubscribeLocalEvent<VendingMachineComponent, BreakageEventArgs>(OnBreak);
SubscribeLocalEvent<VendingMachineComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<VendingMachineComponent, PriceCalculationEvent>(OnVendingPrice);
SubscribeLocalEvent<VendingMachineComponent, EntInsertedIntoContainerMessage>(OnEntityInserted); // Frontier
SubscribeLocalEvent<VendingMachineComponent, EntRemovedFromContainerMessage>(OnEntityRemoved); // Frontier
//SubscribeLocalEvent<VendingMachineComponent, EmpPulseEvent>(OnEmpPulse); // Frontier: Upstream - #28984
//SubscribeLocalEvent<VendingMachineComponent, EntInsertedIntoContainerMessage>(OnEntityInserted); // Frontier //Mono: Moved this logic to CreditReceiverSystem
//SubscribeLocalEvent<VendingMachineComponent, EntRemovedFromContainerMessage>(OnEntityRemoved); // Frontier //Mono: Moved this logic to CreditReceiverSystem
Comment thread
ThanosDeGraf marked this conversation as resolved.

SubscribeLocalEvent<VendingMachineComponent, ActivatableUIOpenAttemptEvent>(OnActivatableUIOpenAttempt);

Expand Down Expand Up @@ -360,17 +360,7 @@ public void AuthorizedVend(EntityUid uid, EntityUid sender, InventoryType type,
if (!HasComp<IronmanComponent>(sender) && TryComp<BankAccountComponent>(sender, out var bank))
bankBalance = bank.Balance;

int cashSlotBalance = 0;
Entity<StackComponent>? cashEntity = null;
if (component.CashSlotName != null
&& component.CurrencyStackType != null
&& ItemSlots.TryGetSlot(uid, component.CashSlotName, out var cashSlot)
&& TryComp<StackComponent>(cashSlot?.ContainerSlot?.ContainedEntity, out var stackComp)
&& stackComp!.StackTypeId == component.CurrencyStackType)
{
cashSlotBalance = stackComp!.Count;
cashEntity = (cashSlot!.ContainerSlot!.ContainedEntity.Value, stackComp!);
}
_cash.TryGetCash(uid, out _, out var cashSlotBalance); //Mono: Moved this logic to CreditReceiverSystem

if (totalPrice > bankBalance + cashSlotBalance)
{
Expand All @@ -385,15 +375,10 @@ public void AuthorizedVend(EntityUid uid, EntityUid sender, InventoryType type,

if (TryEjectVendorItem(uid, type, itemId, component.CanShoot, component))
{
if (cashEntity != null)
{
var newCashSlotBalance = Math.Max(cashSlotBalance - totalPrice, 0);
_stack.SetCount(cashEntity.Value.Owner, newCashSlotBalance, cashEntity.Value.Comp);
component.CashSlotBalance = newCashSlotBalance;
paidFully = true; // Either we paid fully with cash, or we need to withdraw the remainder
}
paidFully = _cash.TryCashPayment(uid, totalPrice, out var _, true); // Mono - Attempt to pay with cash before credit

if (totalPrice > cashSlotBalance && !HasComp<Content.Shared._Mono.Traits.Physical.IronmanComponent>(sender))
paidFully = _bankSystem.TryBankWithdraw(sender, totalPrice - cashSlotBalance);
paidFully = _bankSystem.TryBankWithdraw(sender, totalPrice - cashSlotBalance); // Mono - if cash was not enough, pay the difference with credit

// If we paid completely, pay our station taxes
if (paidFully)
Expand Down Expand Up @@ -673,29 +658,14 @@ private void OnPriceCalculation(EntityUid uid, VendingMachineRestockComponent co
args.Price += priceSets.Max();
}

// Frontier: cash slot logic
private void OnEntityInserted(Entity<VendingMachineComponent> ent, ref EntInsertedIntoContainerMessage args)
{
if (ent.Comp.CashSlotName != null
&& ent.Comp.CurrencyStackType != null
&& ItemSlots.TryGetSlot(ent, ent.Comp.CashSlotName, out var slot)
&& TryComp<StackComponent>(slot?.ContainerSlot?.ContainedEntity, out var stack)
&& stack.StackTypeId == ent.Comp.CurrencyStackType)
{
ent.Comp.CashSlotBalance = stack.Count;
}
else
{
ent.Comp.CashSlotBalance = 0;
}
Dirty(ent, ent.Comp);
}

private void OnEntityRemoved(Entity<VendingMachineComponent> ent, ref EntRemovedFromContainerMessage args)
{
ent.Comp.CashSlotBalance = 0;
Dirty(ent, ent.Comp);
}
// End Frontier: cash slot logic
//private void OnEmpPulse(EntityUid uid, VendingMachineComponent component, ref EmpPulseEvent args) // Frontier: Upstream - #28984
//{
// if (!component.Broken && this.IsPowered(uid, EntityManager))
// {
// args.Affected = true;
// args.Disabled = true;
// component.NextEmpEject = _timing.CurTime;
// }
//}
Comment thread
ThanosDeGraf marked this conversation as resolved.
}
}
8 changes: 8 additions & 0 deletions Content.Server/_Mono/Economy/CreditReceiverSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using Content.Shared._Mono.Economy;

namespace Content.Server._Mono.Economy;

public sealed partial class CreditReceiverSystem : SharedCreditReceiverSystem
{

}
9 changes: 3 additions & 6 deletions Content.Shared/VendingMachines/SharedVendingMachineSystem.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using Content.Shared._Mono.Economy.Component; // Mono
Comment thread
ThanosDeGraf marked this conversation as resolved.
using Content.Shared.DoAfter;
using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems;
Expand Down Expand Up @@ -38,12 +39,8 @@ public override void Initialize()

protected virtual void OnMapInit(EntityUid uid, VendingMachineComponent component, MapInitEvent args)
{
RestockInventoryFromPrototype(uid, component, component.InitialStockQuality);

// Frontier: create the cash slot if this entity has one
if (component.CashSlot != null && component.CashSlotName != null)
ItemSlots.AddItemSlot(uid, component.CashSlotName, component.CashSlot);
// End Frontier
if (TryComp<VendingMachineComponent>(uid, out var vendingMachine)) // Mono
Comment thread
Ilya246 marked this conversation as resolved.
RestockInventoryFromPrototype(uid, vendingMachine, vendingMachine.InitialStockQuality); // Mono
}

public void RestockInventoryFromPrototype(EntityUid uid,
Expand Down
28 changes: 4 additions & 24 deletions Content.Shared/VendingMachines/VendingMachineComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Content.Shared._NF.Bank.Components; // Frontier
using Content.Shared.Containers.ItemSlots; // Frontier
//using Content.Shared.Containers.ItemSlots; // Frontier // Mono
using Content.Shared._Mono.Economy.Component; // Mono

namespace Content.Shared.VendingMachines
{
/// Mono Change: Anything related to actually accepting physical cash or other currencies has been
/// moved over to <see cref="CreditReceiverComponent"/>. <seealso cref="CreditReceiverComponent.CashSlot"/>
Comment on lines +14 to +15

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove, as well unneeded usings

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
public sealed partial class VendingMachineComponent : Component
{
Expand Down Expand Up @@ -218,29 +221,6 @@ public sealed partial class VendingMachineComponent : Component
[DataField(serverOnly: true), ViewVariables(VVAccess.ReadWrite)]
public Dictionary<SectorBankAccount, float> TaxAccounts = new();

// Optional item slot for cash
[DataField]
public ItemSlot? CashSlot = null;

/// <summary>
/// Name of the cash slot, if there is one. Null if there isn't.
/// </summary>
[DataField]
public string? CashSlotName;

/// <summary>
/// The type of currency to accept in the item slot.
/// </summary>
[DataField]
public string? CurrencyStackType;

/// <summary>
/// The current balance in the cash slot.
/// Kept for
/// </summary>
[DataField, AutoNetworkedField]
public int CashSlotBalance;

/// <summary>
/// Mono: Tracks the last purchase price for vending machine purchase tracking.
/// Used to mark spawned entities with purchase information.
Expand Down
37 changes: 37 additions & 0 deletions Content.Shared/_Mono/Economy/Component/CreditReceiverComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using Robust.Shared.GameStates;
using Content.Shared.Containers.ItemSlots;

namespace Content.Shared._Mono.Economy.Component;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
[Access(typeof(SharedCreditReceiverSystem))]
public sealed partial class CreditReceiverComponent : Robust.Shared.GameObjects.Component
{
/// <summary>
/// Item slot for cash.</summary>
/// <remarks>
/// Set this to Null if you want to disable this component
/// in case you can't get rid of it, i.e. YAML inherited.
/// </remarks>
[DataField]
public ItemSlot? CashSlot;

/// <summary>
/// Name of the cash slot, if there is one. Null if there isn't.
/// </summary>
[DataField]
public string? CashSlotName;
Comment on lines +10 to +23

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make non-nullable and remove relevant checks, the comp just shouldn't be added if not needed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above. All vending machines inherit this component since they base-line expect to be credit receivers. It's only some vendors that don't want this component.


/// <summary>
/// The type of currency to accept in the item slot.
/// </summary>
[DataField]
public string? CurrencyStackType;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use non-nullable ProtoId with a default value set to normal credits stack prototype

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A protoID makes sense, as well as the default money ID, but making it non-nullable will be a massive pain the ass YAML side. Instead of only nulling CreditReceiver for the four vendors that dont need it, I have to add the component to every single vendor that DOES accept it EXCEPT the four special goobers.

@Ilya246 Ilya246 May 26, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, you make a new base vendor type and reparent the ones that don't need credit receiver to it
so you have:

id: BaseVendomat
...
id: BaseVendomatCredit
parent: BaseVendomat

and parent vendomats accordingly

or make the first one BaseVendomatNoCredit and make the second one just BaseVendomat


/// <summary>
/// The current balance in the cash slot.
/// Kept for
/// </summary>
[DataField, AutoNetworkedField]
public int CashSlotBalance;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be needed (directly check the stack via method in system instead)

}
Loading
Loading