2023-05-03 01:38:03 -04:00
using System.Linq ;
2023-07-08 14:08:32 +10:00
using System.Numerics ;
2022-09-15 11:53:17 +10:00
using Content.Server.Cargo.Systems ;
2023-05-07 01:26:04 +10:00
using Content.Server.Emp ;
2022-01-30 22:16:41 -06:00
using Content.Server.Power.Components ;
2022-05-27 10:36:12 +10:00
using Content.Server.Power.EntitySystems ;
2022-08-31 14:12:09 +02:00
using Content.Server.UserInterface ;
2022-01-30 22:16:41 -06:00
using Content.Shared.Access.Components ;
using Content.Shared.Access.Systems ;
2022-06-23 00:52:28 -04:00
using Content.Shared.Actions ;
using Content.Shared.Damage ;
2022-05-27 10:36:12 +10:00
using Content.Shared.Destructible ;
2023-02-24 19:01:25 -05:00
using Content.Shared.DoAfter ;
2023-02-19 01:03:06 +00:00
using Content.Shared.Emag.Components ;
2022-05-27 10:36:12 +10:00
using Content.Shared.Emag.Systems ;
2023-05-07 01:26:04 +10:00
using Content.Shared.Emp ;
2023-01-01 18:42:56 -05:00
using Content.Shared.Popups ;
2022-05-27 10:36:12 +10:00
using Content.Shared.Throwing ;
2022-01-30 22:16:41 -06:00
using Content.Shared.VendingMachines ;
using Robust.Server.GameObjects ;
2022-05-27 10:36:12 +10:00
using Robust.Shared.Audio ;
2022-01-30 22:16:41 -06:00
using Robust.Shared.Prototypes ;
using Robust.Shared.Random ;
2023-05-07 01:26:04 +10:00
using Robust.Shared.Timing ;
2022-01-30 22:16:41 -06:00
2022-05-27 10:36:12 +10:00
namespace Content.Server.VendingMachines
2022-01-30 22:16:41 -06:00
{
2022-07-26 12:35:36 +12:00
public sealed class VendingMachineSystem : SharedVendingMachineSystem
2022-01-30 22:16:41 -06:00
{
[Dependency] private readonly IRobustRandom _random = default ! ;
[Dependency] private readonly AccessReaderSystem _accessReader = default ! ;
2022-09-15 11:53:17 +10:00
[Dependency] private readonly AppearanceSystem _appearanceSystem = default ! ;
2022-06-23 00:52:28 -04:00
[Dependency] private readonly SharedActionsSystem _action = default ! ;
2022-09-15 11:53:17 +10:00
[Dependency] private readonly PricingSystem _pricing = default ! ;
[Dependency] private readonly ThrowingSystem _throwingSystem = default ! ;
2022-08-31 14:12:09 +02:00
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
2023-05-07 01:26:04 +10:00
[Dependency] private readonly IGameTiming _timing = default ! ;
2022-09-15 11:53:17 +10:00
private ISawmill _sawmill = default ! ;
2022-01-30 22:16:41 -06:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-07-26 12:35:36 +12:00
2022-09-15 11:53:17 +10:00
_sawmill = Logger . GetSawmill ( "vending" ) ;
2023-09-08 18:16:05 -07:00
SubscribeLocalEvent < VendingMachineComponent , MapInitEvent > ( OnComponentMapInit ) ;
2022-01-30 22:16:41 -06:00
SubscribeLocalEvent < VendingMachineComponent , PowerChangedEvent > ( OnPowerChanged ) ;
SubscribeLocalEvent < VendingMachineComponent , BreakageEventArgs > ( OnBreak ) ;
2022-04-17 03:16:02 -04:00
SubscribeLocalEvent < VendingMachineComponent , GotEmaggedEvent > ( OnEmagged ) ;
2022-06-23 00:52:28 -04:00
SubscribeLocalEvent < VendingMachineComponent , DamageChangedEvent > ( OnDamage ) ;
2022-09-15 11:53:17 +10:00
SubscribeLocalEvent < VendingMachineComponent , PriceCalculationEvent > ( OnVendingPrice ) ;
2023-05-07 01:26:04 +10:00
SubscribeLocalEvent < VendingMachineComponent , EmpPulseEvent > ( OnEmpPulse ) ;
2022-06-23 00:52:28 -04:00
2022-08-31 14:12:09 +02:00
SubscribeLocalEvent < VendingMachineComponent , ActivatableUIOpenAttemptEvent > ( OnActivatableUIOpenAttempt ) ;
SubscribeLocalEvent < VendingMachineComponent , BoundUIOpenedEvent > ( OnBoundUIOpened ) ;
SubscribeLocalEvent < VendingMachineComponent , VendingMachineEjectMessage > ( OnInventoryEjectMessage ) ;
2022-06-23 00:52:28 -04:00
SubscribeLocalEvent < VendingMachineComponent , VendingMachineSelfDispenseEvent > ( OnSelfDispense ) ;
2023-01-01 18:42:56 -05:00
2023-04-03 13:13:48 +12:00
SubscribeLocalEvent < VendingMachineComponent , RestockDoAfterEvent > ( OnDoAfter ) ;
2023-05-03 01:38:03 -04:00
SubscribeLocalEvent < VendingMachineRestockComponent , PriceCalculationEvent > ( OnPriceCalculation ) ;
2022-01-30 22:16:41 -06:00
}
2023-09-08 18:16:05 -07:00
private void OnComponentMapInit ( EntityUid uid , VendingMachineComponent component , MapInitEvent args )
{
_action . AddAction ( uid , ref component . ActionEntity , component . Action , uid ) ;
Dirty ( uid , component ) ;
}
2022-09-15 11:53:17 +10:00
private void OnVendingPrice ( EntityUid uid , VendingMachineComponent component , ref PriceCalculationEvent args )
{
var price = 0.0 ;
2023-05-03 01:38:03 -04:00
foreach ( var entry in component . Inventory . Values )
2022-09-15 11:53:17 +10:00
{
2023-05-03 01:38:03 -04:00
if ( ! PrototypeManager . TryIndex < EntityPrototype > ( entry . ID , out var proto ) )
2022-09-15 11:53:17 +10:00
{
_sawmill . Error ( $"Unable to find entity prototype {entry.ID} on {ToPrettyString(uid)} vending." ) ;
continue ;
}
2023-03-24 15:27:55 +11:00
price + = entry . Amount * _pricing . GetEstimatedPrice ( proto ) ;
2022-09-15 11:53:17 +10:00
}
args . Price + = price ;
}
2022-12-24 23:28:21 -05:00
protected override void OnComponentInit ( EntityUid uid , VendingMachineComponent component , ComponentInit args )
2022-01-30 22:16:41 -06:00
{
2022-12-24 23:28:21 -05:00
base . OnComponentInit ( uid , component , args ) ;
2022-01-30 22:16:41 -06:00
2023-05-03 01:38:03 -04:00
if ( HasComp < ApcPowerReceiverComponent > ( uid ) )
2022-01-30 22:16:41 -06:00
{
2022-08-31 14:12:09 +02:00
TryUpdateVisualState ( uid , component ) ;
2022-01-30 22:16:41 -06:00
}
}
2022-08-31 14:12:09 +02:00
private void OnActivatableUIOpenAttempt ( EntityUid uid , VendingMachineComponent component , ActivatableUIOpenAttemptEvent args )
2022-01-30 22:16:41 -06:00
{
2022-08-31 14:12:09 +02:00
if ( component . Broken )
args . Cancel ( ) ;
}
2022-01-30 22:16:41 -06:00
2022-08-31 14:12:09 +02:00
private void OnBoundUIOpened ( EntityUid uid , VendingMachineComponent component , BoundUIOpenedEvent args )
{
2023-05-03 01:38:03 -04:00
UpdateVendingMachineInterfaceState ( uid , component ) ;
2022-08-31 14:12:09 +02:00
}
2022-05-09 19:22:58 -07:00
2023-05-03 01:38:03 -04:00
private void UpdateVendingMachineInterfaceState ( EntityUid uid , VendingMachineComponent component )
2022-08-31 14:12:09 +02:00
{
2023-05-03 01:38:03 -04:00
var state = new VendingMachineInterfaceState ( GetAllInventory ( uid , component ) ) ;
2022-05-09 19:22:58 -07:00
2023-05-03 01:38:03 -04:00
_userInterfaceSystem . TrySetUiState ( uid , VendingMachineUiKey . Key , state ) ;
2022-01-30 22:16:41 -06:00
}
private void OnInventoryEjectMessage ( EntityUid uid , VendingMachineComponent component , VendingMachineEjectMessage args )
{
2022-05-27 10:36:12 +10:00
if ( ! this . IsPowered ( uid , EntityManager ) )
2022-01-30 22:16:41 -06:00
return ;
if ( args . Session . AttachedEntity is not { Valid : true } entity | | Deleted ( entity ) )
return ;
2022-05-09 19:22:58 -07:00
AuthorizedVend ( uid , entity , args . Type , args . ID , component ) ;
2022-01-30 22:16:41 -06:00
}
2022-10-15 15:08:15 +11:00
private void OnPowerChanged ( EntityUid uid , VendingMachineComponent component , ref PowerChangedEvent args )
2022-01-30 22:16:41 -06:00
{
2022-08-31 14:12:09 +02:00
TryUpdateVisualState ( uid , component ) ;
2022-01-30 22:16:41 -06:00
}
private void OnBreak ( EntityUid uid , VendingMachineComponent vendComponent , BreakageEventArgs eventArgs )
{
vendComponent . Broken = true ;
2022-08-31 14:12:09 +02:00
TryUpdateVisualState ( uid , vendComponent ) ;
2022-01-30 22:16:41 -06:00
}
2023-01-21 10:12:45 -05:00
private void OnEmagged ( EntityUid uid , VendingMachineComponent component , ref GotEmaggedEvent args )
2022-04-17 03:16:02 -04:00
{
2023-02-19 01:03:06 +00:00
// only emag if there are emag-only items
args . Handled = component . EmaggedInventory . Count > 0 ;
2022-04-17 03:16:02 -04:00
}
2022-09-15 11:53:17 +10:00
2022-06-23 00:52:28 -04:00
private void OnDamage ( EntityUid uid , VendingMachineComponent component , DamageChangedEvent args )
{
2022-08-31 14:12:09 +02:00
if ( component . Broken | | component . DispenseOnHitCoolingDown | |
component . DispenseOnHitChance = = null | | args . DamageDelta = = null )
2022-06-23 00:52:28 -04:00
return ;
2022-08-31 14:12:09 +02:00
if ( args . DamageIncreased & & args . DamageDelta . Total > = component . DispenseOnHitThreshold & &
_random . Prob ( component . DispenseOnHitChance . Value ) )
{
if ( component . DispenseOnHitCooldown > 0f )
component . DispenseOnHitCoolingDown = true ;
EjectRandom ( uid , throwItem : true , forceEject : true , component ) ;
}
2022-06-23 00:52:28 -04:00
}
private void OnSelfDispense ( EntityUid uid , VendingMachineComponent component , VendingMachineSelfDispenseEvent args )
{
if ( args . Handled )
return ;
args . Handled = true ;
2022-08-31 14:12:09 +02:00
EjectRandom ( uid , throwItem : true , forceEject : false , component ) ;
}
2023-02-24 19:01:25 -05:00
private void OnDoAfter ( EntityUid uid , VendingMachineComponent component , DoAfterEvent args )
2023-01-01 18:42:56 -05:00
{
2023-02-24 19:01:25 -05:00
if ( args . Handled | | args . Cancelled | | args . Args . Used = = null )
return ;
if ( ! TryComp < VendingMachineRestockComponent > ( args . Args . Used , out var restockComponent ) )
2023-01-01 18:42:56 -05:00
{
2023-02-24 19:01:25 -05:00
_sawmill . Error ( $"{ToPrettyString(args.Args.User)} tried to restock {ToPrettyString(uid)} with {ToPrettyString(args.Args.Used.Value)} which did not have a VendingMachineRestockComponent." ) ;
2023-01-01 18:42:56 -05:00
return ;
}
TryRestockInventory ( uid , component ) ;
2023-05-03 01:38:03 -04:00
Popup . PopupEntity ( Loc . GetString ( "vending-machine-restock-done" , ( "this" , args . Args . Used ) , ( "user" , args . Args . User ) , ( "target" , uid ) ) , args . Args . User , PopupType . Medium ) ;
2023-02-24 19:01:25 -05:00
2023-05-03 01:38:03 -04:00
Audio . PlayPvs ( restockComponent . SoundRestockDone , uid , AudioParams . Default . WithVolume ( - 2f ) . WithVariation ( 0.2f ) ) ;
2023-01-01 18:42:56 -05:00
2023-02-24 19:01:25 -05:00
Del ( args . Args . Used . Value ) ;
2023-01-01 18:42:56 -05:00
2023-02-24 19:01:25 -05:00
args . Handled = true ;
2023-01-01 18:42:56 -05:00
}
2022-08-31 14:12:09 +02:00
/// <summary>
/// Sets the <see cref="VendingMachineComponent.CanShoot"/> property of the vending machine.
/// </summary>
public void SetShooting ( EntityUid uid , bool canShoot , VendingMachineComponent ? component = null )
{
if ( ! Resolve ( uid , ref component ) )
return ;
component . CanShoot = canShoot ;
2022-06-23 00:52:28 -04:00
}
2022-04-17 03:16:02 -04:00
2022-01-30 22:16:41 -06:00
public void Deny ( EntityUid uid , VendingMachineComponent ? vendComponent = null )
{
if ( ! Resolve ( uid , ref vendComponent ) )
return ;
2022-08-31 14:12:09 +02:00
if ( vendComponent . Denying )
return ;
vendComponent . Denying = true ;
2023-05-03 01:38:03 -04:00
Audio . PlayPvs ( vendComponent . SoundDeny , uid , AudioParams . Default . WithVolume ( - 2f ) ) ;
2022-08-31 14:12:09 +02:00
TryUpdateVisualState ( uid , vendComponent ) ;
2022-01-30 22:16:41 -06:00
}
2022-08-31 14:12:09 +02:00
/// <summary>
/// Checks if the user is authorized to use this vending machine
/// </summary>
2023-05-03 01:38:03 -04:00
/// <param name="uid"></param>
2022-08-31 14:12:09 +02:00
/// <param name="sender">Entity trying to use the vending machine</param>
2023-05-03 01:38:03 -04:00
/// <param name="vendComponent"></param>
public bool IsAuthorized ( EntityUid uid , EntityUid sender , VendingMachineComponent ? vendComponent = null )
2022-01-30 22:16:41 -06:00
{
2023-05-03 01:38:03 -04:00
if ( ! Resolve ( uid , ref vendComponent ) )
2022-01-30 22:16:41 -06:00
return false ;
2023-05-03 01:38:03 -04:00
if ( ! TryComp < AccessReaderComponent ? > ( uid , out var accessReader ) )
return true ;
2023-09-03 13:05:22 +12:00
if ( _accessReader . IsAllowed ( sender , uid , accessReader ) | | HasComp < EmaggedComponent > ( uid ) )
2023-05-03 01:38:03 -04:00
return true ;
Popup . PopupEntity ( Loc . GetString ( "vending-machine-component-try-eject-access-denied" ) , uid ) ;
Deny ( uid , vendComponent ) ;
return false ;
2022-01-30 22:16:41 -06:00
}
2022-08-31 14:12:09 +02:00
/// <summary>
/// Tries to eject the provided item. Will do nothing if the vending machine is incapable of ejecting, already ejecting
/// or the item doesn't exist in its inventory.
/// </summary>
2023-05-03 01:38:03 -04:00
/// <param name="uid"></param>
2022-08-31 14:12:09 +02:00
/// <param name="type">The type of inventory the item is from</param>
/// <param name="itemId">The prototype ID of the item</param>
/// <param name="throwItem">Whether the item should be thrown in a random direction after ejection</param>
2023-05-03 01:38:03 -04:00
/// <param name="vendComponent"></param>
2022-05-09 19:22:58 -07:00
public void TryEjectVendorItem ( EntityUid uid , InventoryType type , string itemId , bool throwItem , VendingMachineComponent ? vendComponent = null )
2022-01-30 22:16:41 -06:00
{
if ( ! Resolve ( uid , ref vendComponent ) )
return ;
2022-05-27 10:36:12 +10:00
if ( vendComponent . Ejecting | | vendComponent . Broken | | ! this . IsPowered ( uid , EntityManager ) )
2022-01-30 22:16:41 -06:00
{
return ;
}
2023-05-03 01:38:03 -04:00
var entry = GetEntry ( uid , itemId , type , vendComponent ) ;
2022-05-09 19:22:58 -07:00
2022-01-30 22:16:41 -06:00
if ( entry = = null )
{
2023-05-03 01:38:03 -04:00
Popup . PopupEntity ( Loc . GetString ( "vending-machine-component-try-eject-invalid-item" ) , uid ) ;
2022-01-30 22:16:41 -06:00
Deny ( uid , vendComponent ) ;
return ;
}
if ( entry . Amount < = 0 )
{
2023-05-03 01:38:03 -04:00
Popup . PopupEntity ( Loc . GetString ( "vending-machine-component-try-eject-out-of-stock" ) , uid ) ;
2022-01-30 22:16:41 -06:00
Deny ( uid , vendComponent ) ;
return ;
}
2022-05-09 19:22:58 -07:00
if ( string . IsNullOrEmpty ( entry . ID ) )
2022-01-30 22:16:41 -06:00
return ;
// Start Ejecting, and prevent users from ordering while anim playing
vendComponent . Ejecting = true ;
2022-08-31 14:12:09 +02:00
vendComponent . NextItemToEject = entry . ID ;
vendComponent . ThrowNextItem = throwItem ;
2022-01-30 22:16:41 -06:00
entry . Amount - - ;
2023-05-03 01:38:03 -04:00
UpdateVendingMachineInterfaceState ( uid , vendComponent ) ;
2022-08-31 14:12:09 +02:00
TryUpdateVisualState ( uid , vendComponent ) ;
2023-05-03 01:38:03 -04:00
Audio . PlayPvs ( vendComponent . SoundVend , uid ) ;
2022-01-30 22:16:41 -06:00
}
2022-08-31 14:12:09 +02:00
/// <summary>
/// Checks whether the user is authorized to use the vending machine, then ejects the provided item if true
/// </summary>
2023-05-03 01:38:03 -04:00
/// <param name="uid"></param>
2022-08-31 14:12:09 +02:00
/// <param name="sender">Entity that is trying to use the vending machine</param>
/// <param name="type">The type of inventory the item is from</param>
/// <param name="itemId">The prototype ID of the item</param>
2023-05-03 01:38:03 -04:00
/// <param name="component"></param>
2022-05-09 19:22:58 -07:00
public void AuthorizedVend ( EntityUid uid , EntityUid sender , InventoryType type , string itemId , VendingMachineComponent component )
2022-01-30 22:16:41 -06:00
{
if ( IsAuthorized ( uid , sender , component ) )
{
2022-05-09 19:22:58 -07:00
TryEjectVendorItem ( uid , type , itemId , component . CanShoot , component ) ;
2022-01-30 22:16:41 -06:00
}
}
2022-08-31 14:12:09 +02:00
/// <summary>
/// Tries to update the visuals of the component based on its current state.
/// </summary>
public void TryUpdateVisualState ( EntityUid uid , VendingMachineComponent ? vendComponent = null )
2022-01-30 22:16:41 -06:00
{
if ( ! Resolve ( uid , ref vendComponent ) )
return ;
2022-08-31 14:12:09 +02:00
var finalState = VendingMachineVisualState . Normal ;
2022-01-30 22:16:41 -06:00
if ( vendComponent . Broken )
{
finalState = VendingMachineVisualState . Broken ;
}
else if ( vendComponent . Ejecting )
{
finalState = VendingMachineVisualState . Eject ;
}
2022-08-31 14:12:09 +02:00
else if ( vendComponent . Denying )
{
finalState = VendingMachineVisualState . Deny ;
}
2022-05-27 10:36:12 +10:00
else if ( ! this . IsPowered ( uid , EntityManager ) )
2022-01-30 22:16:41 -06:00
{
finalState = VendingMachineVisualState . Off ;
}
2023-05-03 01:38:03 -04:00
_appearanceSystem . SetData ( uid , VendingMachineVisuals . VisualState , finalState ) ;
2022-01-30 22:16:41 -06:00
}
2022-08-31 14:12:09 +02:00
/// <summary>
/// Ejects a random item from the available stock. Will do nothing if the vending machine is empty.
/// </summary>
2023-05-03 01:38:03 -04:00
/// <param name="uid"></param>
2022-08-31 14:12:09 +02:00
/// <param name="throwItem">Whether to throw the item in a random direction after dispensing it.</param>
/// <param name="forceEject">Whether to skip the regular ejection checks and immediately dispense the item without animation.</param>
2023-05-03 01:38:03 -04:00
/// <param name="vendComponent"></param>
2022-08-31 14:12:09 +02:00
public void EjectRandom ( EntityUid uid , bool throwItem , bool forceEject = false , VendingMachineComponent ? vendComponent = null )
2022-01-30 22:16:41 -06:00
{
if ( ! Resolve ( uid , ref vendComponent ) )
return ;
2022-08-31 14:12:09 +02:00
var availableItems = GetAvailableInventory ( uid , vendComponent ) ;
2022-01-30 22:16:41 -06:00
if ( availableItems . Count < = 0 )
return ;
2022-05-09 19:22:58 -07:00
var item = _random . Pick ( availableItems ) ;
2022-08-31 14:12:09 +02:00
if ( forceEject )
{
vendComponent . NextItemToEject = item . ID ;
vendComponent . ThrowNextItem = throwItem ;
2023-05-03 01:38:03 -04:00
var entry = GetEntry ( uid , item . ID , item . Type , vendComponent ) ;
2022-08-31 14:12:09 +02:00
if ( entry ! = null )
entry . Amount - - ;
2023-05-03 01:38:03 -04:00
EjectItem ( uid , vendComponent , forceEject ) ;
2022-08-31 14:12:09 +02:00
}
else
2023-05-03 01:38:03 -04:00
{
2022-08-31 14:12:09 +02:00
TryEjectVendorItem ( uid , item . Type , item . ID , throwItem , vendComponent ) ;
2023-05-03 01:38:03 -04:00
}
2022-08-31 14:12:09 +02:00
}
2023-05-03 01:38:03 -04:00
private void EjectItem ( EntityUid uid , VendingMachineComponent ? vendComponent = null , bool forceEject = false )
2022-08-31 14:12:09 +02:00
{
2023-05-03 01:38:03 -04:00
if ( ! Resolve ( uid , ref vendComponent ) )
return ;
2022-08-31 14:12:09 +02:00
// No need to update the visual state because we never changed it during a forced eject
if ( ! forceEject )
2023-05-03 01:38:03 -04:00
TryUpdateVisualState ( uid , vendComponent ) ;
2022-08-31 14:12:09 +02:00
if ( string . IsNullOrEmpty ( vendComponent . NextItemToEject ) )
{
vendComponent . ThrowNextItem = false ;
return ;
}
2022-09-15 11:53:17 +10:00
2023-05-03 01:38:03 -04:00
var ent = Spawn ( vendComponent . NextItemToEject , Transform ( uid ) . Coordinates ) ;
2022-08-31 14:12:09 +02:00
if ( vendComponent . ThrowNextItem )
{
var range = vendComponent . NonLimitedEjectRange ;
var direction = new Vector2 ( _random . NextFloat ( - range , range ) , _random . NextFloat ( - range , range ) ) ;
_throwingSystem . TryThrow ( ent , direction , vendComponent . NonLimitedEjectForce ) ;
}
vendComponent . NextItemToEject = null ;
vendComponent . ThrowNextItem = false ;
}
2023-05-03 01:38:03 -04:00
private VendingMachineInventoryEntry ? GetEntry ( EntityUid uid , string entryId , InventoryType type , VendingMachineComponent ? component = null )
2022-08-31 14:12:09 +02:00
{
2023-05-03 01:38:03 -04:00
if ( ! Resolve ( uid , ref component ) )
return null ;
2022-08-31 14:12:09 +02:00
2023-05-03 01:38:03 -04:00
if ( type = = InventoryType . Emagged & & HasComp < EmaggedComponent > ( uid ) )
2022-08-31 14:12:09 +02:00
return component . EmaggedInventory . GetValueOrDefault ( entryId ) ;
if ( type = = InventoryType . Contraband & & component . Contraband )
return component . ContrabandInventory . GetValueOrDefault ( entryId ) ;
return component . Inventory . GetValueOrDefault ( entryId ) ;
}
public override void Update ( float frameTime )
{
base . Update ( frameTime ) ;
2023-05-03 01:38:03 -04:00
var query = EntityQueryEnumerator < VendingMachineComponent > ( ) ;
while ( query . MoveNext ( out var uid , out var comp ) )
2022-08-31 14:12:09 +02:00
{
if ( comp . Ejecting )
{
comp . EjectAccumulator + = frameTime ;
if ( comp . EjectAccumulator > = comp . EjectDelay )
{
comp . EjectAccumulator = 0f ;
comp . Ejecting = false ;
2023-05-03 01:38:03 -04:00
EjectItem ( uid , comp ) ;
2022-08-31 14:12:09 +02:00
}
}
if ( comp . Denying )
{
comp . DenyAccumulator + = frameTime ;
if ( comp . DenyAccumulator > = comp . DenyDelay )
{
comp . DenyAccumulator = 0f ;
comp . Denying = false ;
2023-05-03 01:38:03 -04:00
TryUpdateVisualState ( uid , comp ) ;
2022-08-31 14:12:09 +02:00
}
}
if ( comp . DispenseOnHitCoolingDown )
{
comp . DispenseOnHitAccumulator + = frameTime ;
if ( comp . DispenseOnHitAccumulator > = comp . DispenseOnHitCooldown )
{
comp . DispenseOnHitAccumulator = 0f ;
comp . DispenseOnHitCoolingDown = false ;
}
}
}
2023-05-07 01:26:04 +10:00
var disabled = EntityQueryEnumerator < EmpDisabledComponent , VendingMachineComponent > ( ) ;
while ( disabled . MoveNext ( out var uid , out _ , out var comp ) )
{
if ( comp . NextEmpEject < _timing . CurTime )
{
EjectRandom ( uid , true , false , comp ) ;
comp . NextEmpEject + = TimeSpan . FromSeconds ( 5 * comp . EjectDelay ) ;
}
}
2022-01-30 22:16:41 -06:00
}
2023-01-01 18:42:56 -05:00
public void TryRestockInventory ( EntityUid uid , VendingMachineComponent ? vendComponent = null )
{
if ( ! Resolve ( uid , ref vendComponent ) )
return ;
RestockInventoryFromPrototype ( uid , vendComponent ) ;
2023-05-03 01:38:03 -04:00
UpdateVendingMachineInterfaceState ( uid , vendComponent ) ;
2023-01-01 18:42:56 -05:00
TryUpdateVisualState ( uid , vendComponent ) ;
}
2023-05-03 01:38:03 -04:00
private void OnPriceCalculation ( EntityUid uid , VendingMachineRestockComponent component , ref PriceCalculationEvent args )
{
List < double > priceSets = new ( ) ;
// Find the most expensive inventory and use that as the highest price.
foreach ( var vendingInventory in component . CanRestock )
{
double total = 0 ;
if ( PrototypeManager . TryIndex ( vendingInventory , out VendingMachineInventoryPrototype ? inventoryPrototype ) )
{
foreach ( var ( item , amount ) in inventoryPrototype . StartingInventory )
{
if ( PrototypeManager . TryIndex ( item , out EntityPrototype ? entity ) )
total + = _pricing . GetEstimatedPrice ( entity ) * amount ;
}
}
priceSets . Add ( total ) ;
}
args . Price + = priceSets . Max ( ) ;
}
2023-05-07 01:26:04 +10:00
private void OnEmpPulse ( EntityUid uid , VendingMachineComponent component , ref EmpPulseEvent args )
{
if ( ! component . Broken & & this . IsPowered ( uid , EntityManager ) )
{
args . Affected = true ;
args . Disabled = true ;
component . NextEmpEject = _timing . CurTime ;
}
}
2022-01-30 22:16:41 -06:00
}
}