MenuCard.cs
using Microsoft.VisualBasic;
using Sandbox;
using Sandbox.UI;
using System.Runtime;
using System.Threading.Tasks;

public class MenuCard : Card
{
	public Angles CurrAngles { get; set; }
	public Angles AngleRotSpeed { get; set; }

	private float _fallSpeed;

	private float _currScale;

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

		_fallSpeed = Game.Random.Float( 20f, 100f );

		AngleRotSpeed = new Angles( 0f, Game.Random.Float( -1, 1f ), 0f ) * Game.Random.Float( 0f, 50f );

		var cardType = (CardType)Game.Random.Int(1, Enum.GetValues( typeof( CardType ) ).Length - 1);
		//while ( cardType == CardType.StockMarket || cardType == CardType.StockMarketDown || cardType == CardType.Key || cardType == CardType.AlarmClock || cardType == CardType.ATM )
		//	cardType = (CardType)Game.Random.Int( 1, Enum.GetValues( typeof( CardType ) ).Length - 1 );

		CurrAngles = WorldRotation = new Angles(
			Card.HasHP(cardType) ? 0f : (Game.Random.Float( 0f, 1f ) < 0.6f ? 180f : 0f),
			Game.Random.Float( 0f, 360f ),
			0f
		);

		GameObject.Name = $"menu card ({cardType})";
		Init( cardType );

		_currScale = 1f;
	}

	public override void Init(CardType cardType)
	{
		base.Init( cardType );

		IconObj.SetParent( Model );

		if ( Card.HasHP( cardType ) )
		{
			HP = GetMaxHP(cardType);
			IconObj.Enabled = true;
		}
	}

	protected override void OnUpdate()
	{
		HandleShaking();

		//Gizmo.Draw.Color = Color.White.WithAlpha( 1f );
		//Gizmo.Draw.Text( $"{ShakeOffset}", new global::Transform( WorldPosition ), size: 16 );

		WorldPosition += new Vector3( 0f, -1f, 0f ) * _fallSpeed * Time.Delta;

		Model.LocalPosition = new Vector3( ShakeOffset.x, ShakeOffset.y, 0f );

		CurrAngles += AngleRotSpeed * Time.Delta;
		WorldRotation = CurrAngles;

		if( WorldPosition.y < -200f)
		{
			GameObject.Destroy();
		}

		_currScale = Utils.DynamicEaseTo( _currScale, IsHovered ? 1.1f : 1f, 0.3f, Time.Delta );
		Model.LocalScale = new Vector3( _currScale, _currScale, 0.025f );

		CardIconScale = _currScale;

		IsHovered = false;
	}

	public void PlayMenuHurtSfx()
	{
		switch ( CardType )
		{
			case CardType.Ogre: Manager.Instance.PlayCardSfx( "ogre_hurt", this, volume: 1.3f, pitch: Utils.Map( HP, GetMaxHP( CardType ), 0, 1.2f, 0.7f ) ); break;
			case CardType.Clown: Manager.Instance.PlayCardSfx( "clown_honk", this, volume: 0.8f, pitch: Utils.Map( HP, GetMaxHP( CardType ), 0, 0.55f, 0.4f ) ); break;
			case CardType.Police: Manager.Instance.PlayCardSfx( "police_hurt", this, volume: 1.2f, pitch: Utils.Map( HP, GetMaxHP( CardType ), 0, 1.2f, 0.7f ) ); break;
			case CardType.Wizard: Manager.Instance.PlayCardSfx( "wizard_hurt", this, volume: 2.5f, pitch: Utils.Map( HP, GetMaxHP( CardType ), 0, 1.2f, 0.7f ) ); break;
			case CardType.King: Manager.Instance.PlayCardSfx( "king_hurt", this, volume: 1.9f, pitch: Utils.Map( HP, GetMaxHP( CardType ), 0, 1.2f, 0.7f ) ); break;
		}
	}

	// todo: 
	public void PlayMenuDeathSfx()
	{
		switch ( CardType )
		{
			case CardType.Ogre: Manager.Instance.PlayCardSfx( "ogre_hurt", this, volume: 1.2f, pitch: 0.6f ); break;
			case CardType.Clown: Manager.Instance.PlayCardSfx( "clown_honk", this, volume: 0.6f, pitch: 0.35f ); break;
			case CardType.Police: Manager.Instance.PlayCardSfx( "police_hurt", this, volume: 1.2f, pitch: 0.6f ); break;
			case CardType.Wizard: Manager.Instance.PlayCardSfx( "wizard_hurt", this, volume: 2.1f, pitch: 0.6f ); break;
			case CardType.King: Manager.Instance.PlayCardSfx( "king_hurt", this, volume: 1.9f, pitch: 0.6f ); break;
		}
	}
}