Player/Resources/CarStatValues.cs

Record struct holding tunable car stats and utilities. It defines speed, acceleration, braking, turning, drift and boost parameters, computes UI display ratings (1-5) and provides a Default instance.

namespace Machines.Resources;

/// <summary>
/// Stats container for a car resource
/// </summary>
public record struct CarStatValues
{
	public CarStatValues() { }

	/// <summary>
	/// Maximum forward speed (units/s).
	/// </summary>
	[Property]
	public float MaxSpeed { get; set; } = 800f;

	/// <summary>
	/// Maximum reverse speed (units/s).
	/// </summary>
	[Property]
	public float ReverseSpeed { get; set; } = 300f;

	/// <summary>
	/// Acceleration rate (units/s²).
	/// </summary>
	[Property]
	public float Acceleration { get; set; } = 1200f;

	/// <summary>
	/// Braking / reverse deceleration (units/s²).
	/// </summary>
	[Property]
	public float BrakeForce { get; set; } = 1600f;

	/// <summary>
	/// Base turn rate in degrees per second.
	/// </summary>
	[Property]
	public float TurnRate { get; set; } = 280f;

	/// <summary>
	/// Passive drag when no input (units/s²).
	/// </summary>
	[Property]
	public float Drag { get; set; } = 600f;

	/// <summary>
	/// Turn rate multiplier while drifting (higher = more slide).
	/// </summary>
	[Property]
	public float DriftTurnMultiplier { get; set; } = 1.8f;

	/// <summary>
	/// Minimum drift time needed to earn a boost on release.
	/// </summary>
	[Property]
	public float MinDriftTimeForBoost { get; set; } = 0.5f;

	/// <summary>
	/// Instant velocity added on dash (units/s).
	/// </summary>
	[Property]
	public float BoostImpulse { get; set; } = 400f;

	/// <summary>
	/// Sideways influence of steering on the dash direction (0 = forward, 1 = full side).
	/// </summary>
	[Property]
	public float DashSideStrength { get; set; } = 0.7f;

	/// <summary>
	/// Hill acceleration compensation (1.0 roughly doubles accel on a 45 deg slope, 0 = off).
	/// </summary>
	[Property]
	public float HillStrength { get; set; } = 1.0f;

	/// <summary>
	/// 1-5 display ratings for UI stat bars.
	/// </summary>
	public readonly record struct DisplayRatings( int TopSpeed, int Accel, int Handling, int Braking );

	/// <summary>
	/// Computes 1-5 display ratings using fixed reference ranges.
	/// </summary>
	public DisplayRatings GetDisplayRatings()
	{
		return new DisplayRatings(
			Rate( MaxSpeed, 600f, 750 ),
			Rate( Acceleration, 700f, 1200f ),
			Rate( TurnRate, 200f, 400f ),
			Rate( BrakeForce, 600, 900 )
		);
	}

	/// <summary>
	/// Maps a value in [min, max] to an integer rating 1-5.
	/// </summary>
	private static int Rate( float value, float min, float max )
	{
		if ( max <= min )
			return 3;

		var t = ((value - min) / (max - min)).Clamp( 0f, 1f );
		return System.Math.Clamp( (int)System.MathF.Round( 1f + t * 4f ), 1, 5 );
	}

	/// <summary>
	/// Returns sensible default stats for a standard car.
	/// </summary>
	public static CarStatValues Default => new()
	{
		MaxSpeed = 800f,
		ReverseSpeed = 300f,
		Acceleration = 1200f,
		BrakeForce = 1600f,
		TurnRate = 280f,
		Drag = 600f,
		DriftTurnMultiplier = 1.8f,
		MinDriftTimeForBoost = 0.5f,
		BoostImpulse = 400f,
		DashSideStrength = 0.7f,
		HillStrength = 1.0f
	};
}