Vehicles/VehicleSheet.cs

An editable vehicle sheet used by the in-game admin menu. Holds the same fields as the web panel, converts to and from the immutable VehicleModel record and defines the field list with min/max bounds for the form.

namespace HorizonRP;

/// <summary>
/// Une fiche en cours de réglage dans le menu admin en jeu : les mêmes champs que le panneau
/// web, modifiables (VehicleModel est un enregistrement figé). Bornes : VEHICLE_LIMITS de l'API,
/// qui les revérifie de toute façon.
/// </summary>
public sealed class VehicleSheet
{
	public string Id { get; set; }
	public string Name { get; set; }
	public string Description { get; set; }
	public string Model { get; set; }
	public int Price { get; set; }
	public bool Shop { get; set; }
	public string Drive { get; set; } = "AR";
	public string EngineSound { get; set; } = "";
	public Dictionary<string, float> Numbers { get; set; } = new();

	/// <summary>(clé, libellé, minimum, maximum) : l'ordre du formulaire du panneau web.</summary>
	public static (string Key, string Label, float Min, float Max)[] Fields => new (string, string, float, float)[]
	{
		("MaxSpeedKmh", "Vitesse maxi (km/h)", 20, 400),
		("Acceleration", "Accélération (km/h par s ; 100 ÷ = le 0 à 100)", 2, 90),
		("Mass", "Masse (kg)", 200, 30000),
		("BrakeG", "Freinage (g)", 0.2f, 2.5f),
		("Grip", "Adhérence des pneus", 0.3f, 2.5f),
		("SteerAngle", "Braquage maxi (°)", 8, 60),
		("HandbrakeGrip", "Adhérence arrière au frein à main", 0.05f, 1),
		("SuspensionTravel", "Débattement de la suspension (po)", 2, 24),
		("Stiffness", "Raideur de la suspension", 0.3f, 3),
		("Damping", "Amortissement", 0.3f, 3),
		("AntiRoll", "Barre antiroulis", 0, 4),
		("Seats", "Places (conducteur compris)", 1, 8),
		("TrunkKg", "Capacité du coffre (kg)", 0, 3000),
		("Scale", "Taille du modèle", 0.3f, 3),
		("YawOffset", "Rotation du modèle (°)", -180, 180),
		("SeatHeight", "Hauteur des sièges (po)", -24, 24),
		("SeatForward", "Avancée des sièges (po)", -40, 40),
		("EnginePitch", "Hauteur du moteur", 0.4f, 2.5f),
	};

	public static VehicleSheet From( VehicleModel m ) => new()
	{
		Id = m.Id, Name = m.Name, Description = m.Description, Model = m.Model, Price = m.Price, Shop = m.Shop,
		Drive = m.Drive, EngineSound = m.EngineSound ?? "",
		Numbers = new()
		{
			["MaxSpeedKmh"] = m.MaxSpeedKmh, ["Acceleration"] = m.Acceleration, ["Mass"] = m.Mass, ["BrakeG"] = m.BrakeG,
			["Grip"] = m.Grip, ["SteerAngle"] = m.SteerAngle, ["HandbrakeGrip"] = m.HandbrakeGrip,
			["SuspensionTravel"] = m.SuspensionTravel, ["Stiffness"] = m.Stiffness, ["Damping"] = m.Damping,
			["AntiRoll"] = m.AntiRoll, ["Seats"] = m.Seats, ["TrunkKg"] = m.TrunkKg, ["Scale"] = m.Scale,
			["YawOffset"] = m.YawOffset, ["SeatHeight"] = m.SeatHeight, ["SeatForward"] = m.SeatForward, ["EnginePitch"] = m.EnginePitch,
		},
	};

	float N( string key, float fallback ) => Numbers.TryGetValue( key, out var v ) ? v : fallback;

	public VehicleModel ToModel() => new( Id, Name, Description ?? "", Price, Model, N( "MaxSpeedKmh", 180 ), N( "Acceleration", 17 ), N( "Mass", 1400 ) )
	{
		BrakeG = N( "BrakeG", 1 ), Grip = N( "Grip", 1.1f ), SteerAngle = N( "SteerAngle", 34 ), HandbrakeGrip = N( "HandbrakeGrip", 0.45f ),
		SuspensionTravel = N( "SuspensionTravel", 7 ), Stiffness = N( "Stiffness", 1 ), Damping = N( "Damping", 1 ), AntiRoll = N( "AntiRoll", 1 ),
		Seats = (int)MathF.Round( N( "Seats", 2 ) ), TrunkKg = N( "TrunkKg", 80 ), Scale = N( "Scale", 1.15f ), YawOffset = N( "YawOffset", 0 ),
		SeatHeight = N( "SeatHeight", 0 ), SeatForward = N( "SeatForward", 0 ), EnginePitch = N( "EnginePitch", 1 ), Drive = Drive, Shop = Shop, EngineSound = EngineSound ?? "",
	};
}