Stamina.cs
using Sandbox;
using Sandbox.Rendering;
using System;

namespace Maxine;


[Title( "Maxine's Simple Stamina Component" )]
public sealed class Stamina : Component
{
	/// <summary>
	/// The current available stamina. Use ConsumeStamina() and RegainStamina() unless you want to bypass their event triggers.
	/// </summary>
	public float CurrentStamina = 1000f;

	/// <summary>
	/// The maximum amount of stamina this component can wield.
	/// </summary>
	[Property] public float MaxStamina = 1000f;

	/// <summary>
	/// The amount of time passed before recovering stamina.
	/// </summary>
	[Property] public float StaminaRecoveryAfterSeconds = 0.25f;


	[Property] public float DelayBeforeStaminaRecovery = 2f;

	/// <summary>
	/// How much stamina is recovered after StaminaRecoveryAfterSeconds triggers.
	/// </summary>
	[Property] public float StaminaRecoveryAmount = 10f;

	/// <summary>
	/// Event for when CurrentStamina loses some of its charge.
	/// Can be used for updating UI for example.
	/// </summary>
	[Property] public Action<float> OnStaminaConsumed { get; set; }

	/// <summary>
	/// Event for when CurrentStamina gains some stamina.
	/// Can be used for updating UI for example.
	/// </summary>
	[Property] public Action<float> OnStaminaRegenerated { get; set; }

	[Property] private bool enableDebugHud = false;

	private TimeSince lastRegenCheck = 0;
	private TimeSince delayBeforeRegen = 0;


	protected override void OnAwake()
    {
        base.OnAwake();
		CurrentStamina = MaxStamina;
    }

	protected override void OnUpdate()
	{
		base.OnUpdate();

		if ( enableDebugHud ) DrawDebugHud();

		if ( CurrentStamina >= MaxStamina ) return;
		if (lastRegenCheck.Relative >= StaminaRecoveryAfterSeconds && delayBeforeRegen.Relative >= DelayBeforeStaminaRecovery)
		{
			RegainStamina( StaminaRecoveryAmount );
		}
	}

	public void RegainStamina( float stamina )
	{
		float currentStamina = CurrentStamina;
		CurrentStamina = Math.Clamp( CurrentStamina + stamina, 0, MaxStamina );
		lastRegenCheck = 0;
		OnStaminaRegenerated?.Invoke( stamina );
	}

	public void ConsumeStamina( float amountOfStaminaToConsume )
	{
		delayBeforeRegen = 0;
		if (CurrentStamina <= 0 )
		{
			return;
		}
		CurrentStamina = Math.Clamp( CurrentStamina - amountOfStaminaToConsume, 0, MaxStamina );
		lastRegenCheck = 0;
		OnStaminaConsumed?.Invoke( amountOfStaminaToConsume );
	}

	private void DrawDebugHud()
	{
		if ( Scene.Camera is null )
			return;
		float staminaPercentage = (float)CurrentStamina / MaxStamina;
		float lineHeight = Screen.Height * staminaPercentage;
		var hud = Scene.Camera.Hud;
		hud.DrawText( new TextRendering.Scope( CurrentStamina.ToString(), Color.Red, 32 ), new Vector2(Screen.Width * 0.5f,Screen.Height * 0.95f) );
		hud.DrawLine(new Vector2(0, Screen.Height ), new Vector2( lineHeight * 2, Screen.Height  ) , 4f,  Color.Green );
	}
}