A vending machine component for the local player. Tracks the nearest machine within InteractionRange, binds slot1 to buy a speed drink and slot2/use to buy a medkit, spends MetaProgression credits, plays a sound and camera shake.
using Sandbox;
using System;
using System.Linq;
public sealed class VendingMachine : Component
{
public static VendingMachine NearestMachine { get; private set; }
[Property] public float InteractionRange { get; set; } = 140f;
[Property] public int SpeedDrinkCost { get; set; } = 25;
[Property] public int MedkitCost { get; set; } = 40;
[Property] public string BuySound { get; set; } = "music/buttonhover.sound";
[Sync] private TimeSince _timeSincePurchase { get; set; } = 1f;
protected override void OnUpdate()
{
var localPlayer = PlayerHealth.LocalInstance;
if ( !localPlayer.IsValid() || localPlayer.IsDead || localPlayer.IsDowned )
{
if ( NearestMachine == this ) NearestMachine = null;
return;
}
float dist = Vector3.DistanceBetween( WorldPosition, localPlayer.WorldPosition );
if ( dist <= InteractionRange )
{
NearestMachine = this;
// Quick hotkeys when near vending machine: Key 1 for Drink, Key 2 for Medkit
if ( Input.Pressed( "slot1" ) && _timeSincePurchase > 0.6f )
{
TryBuySpeedDrink();
}
else if ( ( Input.Pressed( "slot2" ) || Input.Pressed( "use" ) ) && _timeSincePurchase > 0.6f )
{
TryBuyMedkit();
}
}
else if ( NearestMachine == this )
{
NearestMachine = null;
}
}
public bool TryBuySpeedDrink()
{
var meta = MetaProgression.Instance;
if ( meta == null || meta.Credits < SpeedDrinkCost )
{
Sound.Play( "music/buttonhover.sound", WorldPosition );
Log.Info( "[VendingMachine] Not enough coins for Speed Drink!" );
return false;
}
meta.AddCredits( -SpeedDrinkCost );
_timeSincePurchase = 0f;
var abilities = PlayerAbilities.LocalInstance;
if ( abilities.IsValid() )
{
abilities.TryActivateSpeedJuice();
}
PlayPurchaseFeedback();
Log.Info( "[VendingMachine] Purchased Speed Drink!" );
return true;
}
public bool TryBuyMedkit()
{
var meta = MetaProgression.Instance;
if ( meta == null || meta.Credits < MedkitCost )
{
Sound.Play( "music/buttonhover.sound", WorldPosition );
Log.Info( "[VendingMachine] Not enough coins for Medkit!" );
return false;
}
var health = PlayerHealth.LocalInstance;
if ( !health.IsValid() || health.IsDead ) return false;
meta.AddCredits( -MedkitCost );
_timeSincePurchase = 0f;
health.Heal( 50f );
PlayPurchaseFeedback();
Log.Info( "[VendingMachine] Purchased Medkit (+50 HP)!" );
return true;
}
private void PlayPurchaseFeedback()
{
if ( !string.IsNullOrEmpty( BuySound ) )
{
Sound.Play( BuySound, WorldPosition );
}
CameraJuice.Instance?.Shake( 10f, 3f );
}
protected override void OnDestroy()
{
if ( NearestMachine == this ) NearestMachine = null;
base.OnDestroy();
}
}