City/CityKinds.cs

Static catalog for the city building menu. Declares the CityKind record, the placement kinds (decor, garage, ATM, job NPC, spawn) and a Catalog list of built-in and imported prop models, with a Prop helper building the horizon props paths.

namespace HorizonRP;

/// <summary>
/// Les sortes d'objets que le staff pose en jeu (menu F6). Déclarées à
/// l'identique dans PLACEMENT_KINDS de l'API (api/api.php) : l'API refuse une
/// sorte qu'elle ne connaît pas.
/// </summary>
public sealed record CityKind( string Id, string Name, string Icon, string Description, string DefaultModel );

/// <summary>Un modèle proposé dans le catalogue du menu de construction.</summary>
public sealed record CatalogModel( string Name, string Category, string Model );

public static class CityKinds
{
	public const string Decor = "decor";
	public const string Garage = "garage";
	public const string Atm = "distributeur";
	public const string JobNpc = "pnj";
	public const string Spawn = "apparition";

	public static readonly IReadOnlyList<CityKind> All = new List<CityKind>
	{
		new( Decor, "Décor", "chair", "Un objet de décor : mobilier, voirie, déco.", "models/citizen_props/crate01.vmdl" ),
		new( Garage, "Garage", "garage", "Concession et garage : acheter, sortir, ranger (touche E). Les véhicules sortent devant lui.", "models/citizen_props/roadcone01.vmdl" ),
		new( Atm, "Distributeur", "local_atm", "Le distributeur HZ Bank : retrait, dépôt et solde (touche E).", HorizonRP.Atm.ModelPath ),
		new( JobNpc, "PNJ de métier", "badge", "Un PNJ où l'on prend un métier (touche E).", "models/citizen_human/human.vmdl" ),
		new( Spawn, "Point d'apparition", "person_pin_circle", "Où les joueurs arrivent. Invisible hors staff.", "models/editor/playerstart.vmdl" ),
	};

	public static CityKind Get( string id ) => All.FirstOrDefault( x => x.Id == id ) ?? All[0];

	/// <summary>
	/// Les modèles fournis avec s&box, puis nos props importés. Le champ libre du menu accepte aussi un
	/// chemin « mount://… » (jeu monté, GMod par exemple : chaque joueur doit
	/// alors posséder ce jeu pour voir l'objet) ou un paquet du Workshop
	/// « org.paquet », téléchargé à la volée.
	/// </summary>
	public static readonly IReadOnlyList<CatalogModel> Catalog = new List<CatalogModel>
	{
		new( "Caisse", "Stockage", "models/citizen_props/crate01.vmdl" ),
		new( "Carton", "Stockage", "models/citizen_props/cardboardbox01.vmdl" ),
		new( "Cône", "Voirie", "models/citizen_props/roadcone01.vmdl" ),
		new( "Séparateur béton", "Voirie", "models/citizen_props/concreteroaddivider01.vmdl" ),
		new( "Bac à sel", "Voirie", "models/citizen_props/gritbin01_combined.vmdl" ),
		new( "Poubelle", "Voirie", "models/citizen_props/trashcan01.vmdl" ),
		new( "Poubelle (2)", "Voirie", "models/citizen_props/trashcan02.vmdl" ),
		new( "Bac de tri", "Voirie", "models/citizen_props/recyclingbin01.vmdl" ),
		new( "Sac poubelle", "Voirie", "models/citizen_props/trashbag02.vmdl" ),
		new( "Chaise", "Mobilier", "models/citizen_props/chair01.vmdl" ),
		new( "Chaise (2)", "Mobilier", "models/citizen_props/chair02.vmdl" ),
		new( "Chaise (3)", "Mobilier", "models/citizen_props/chair03.vmdl" ),
		new( "Fauteuil cuir", "Mobilier", "models/citizen_props/chair04blackleather.vmdl" ),
		new( "Fauteuil tissu", "Mobilier", "models/citizen_props/chair05bluefabric.vmdl" ),
		new( "Lavabo", "Mobilier", "models/citizen_props/bathroomsink01.vmdl" ),
		new( "Vieux four", "Mobilier", "models/citizen_props/oldoven.vmdl" ),
		new( "Roue", "Divers", "models/citizen_props/wheel01.vmdl" ),
		new( "Pneu", "Divers", "models/citizen_props/wheel02.vmdl" ),
		new( "Ballon de plage", "Divers", "models/citizen_props/beachball.vmdl" ),
		new( "Journal", "Divers", "models/citizen_props/newspaper01.vmdl" ),
		new( "Bloc", "Construction", "models/dev/box.vmdl" ),
		new( "Sphère", "Construction", "models/dev/sphere.vmdl" ),
		new( "Plaque", "Construction", "models/dev/plane.vmdl" ),
		new( "Mannequin", "Construction", "models/citizen_mannequin/mannequin.vmdl" ),
		// Les props importés (outils/props/preparer_props.py, 30/10/2026).
		Prop( "Distributeur HZ Bank", "Banque", "atm" ),
		Prop( "Digicode", "Sécurité", "digicode" ),
		Prop( "Terminal de paiement", "Commerce", "terminal_cb" ),
		Prop( "Poubelle bleue", "Voirie", "poubelle_bleue" ),
		Prop( "Poubelle verte", "Voirie", "poubelle_verte" ),
		Prop( "Benne à ordures", "Voirie", "benne_verte" ),
		Prop( "Bloc béton", "Voirie", "bloc_beton" ),
		Prop( "Bloc béton (extrémité)", "Voirie", "bloc_beton_fin" ),
		Prop( "Barrière de chantier longue", "Voirie", "barriere_longue" ),
		Prop( "Barrière de chantier courte", "Voirie", "barriere_courte" ),
		Prop( "Séparateur rouge", "Voirie", "barriere_rouge" ),
		Prop( "Séparateur blanc", "Voirie", "barriere_blanche" ),
		Prop( "Cône de signalisation", "Voirie", "cone" ),
		Prop( "Cône haut", "Voirie", "cone_haut" ),
		Prop( "Fût de signalisation", "Voirie", "fut_signalisation" ),
		Prop( "Fût d'eau", "Voirie", "fut_eau_1" ),
		Prop( "Fût d'eau (2)", "Voirie", "fut_eau_2" ),
		Prop( "Fût d'eau (3)", "Voirie", "fut_eau_3" ),
		Prop( "Ralentisseur", "Voirie", "ralentisseur_1" ),
		Prop( "Ralentisseur (2)", "Voirie", "ralentisseur_2" ),
		Prop( "Ralentisseur (3)", "Voirie", "ralentisseur_3" ),
		Prop( "Ralentisseur (4)", "Voirie", "ralentisseur_4" ),
		Prop( "Panneau stop", "Signalisation", "panneau_stop" ),
		Prop( "Panneau ralentir", "Signalisation", "panneau_ralentir" ),
		Prop( "Panneau tourner à droite", "Signalisation", "panneau_droite" ),
		Prop( "Panneau demi-tour", "Signalisation", "panneau_demi_tour" ),
	};

	static CatalogModel Prop( string name, string category, string id ) => new( name, category, $"models/horizon/props/{id}/{id}.vmdl" );
}