Razor panel that renders the fictional New Horizon state ID card for a roleplay character. Front side shows a live 3D head render via ScenePanel/Preview3D plus name, birth date, sex, nationality, citizen number and issue/expiry dates; the back shows a generated barcode and legal text. Override properties let the character creation form feed in unsaved name, birth, sex and appearance.
@using Sandbox;
@using Sandbox.UI;
@namespace HorizonRP
@inherits Panel
@*
La carte d'identité de l'État (fictif) de New Horizon. Recto : photo (le
personnage en 3D, de face), nom, naissance, sexe, nationalité, numéro de
citoyen, dates. Verso : code-barres et mention légale. Sert au portefeuille, à
la carte qu'un autre joueur vous montre, et à la création du personnage, où
nom, naissance, sexe et visage viennent du formulaire, en direct.
*@
<root class="@(Flipped ? "flipped" : "")">
@if ( Player is null )
{
}
else if ( !Flipped )
{
<div class="head">
<div class="state">@Documents.State</div>
<div class="kind">CARTE D'IDENTITÉ</div>
</div>
<div class="body">
<div class="photo"><ScenePanel @ref="Photo" class="photo-3d"></ScenePanel></div>
<div class="fields">
<div class="id-label">NOM</div>
<div class="name">@ShownName</div>
<div class="row">
<div class="cell"><div class="id-label">DATE DE NAISSANCE</div><div class="value">@Format.Date( ShownBirth )</div></div>
<div class="cell"><div class="id-label">SEXE</div><div class="value">@(ShownSex ?? "—")</div></div>
</div>
<div class="row">
<div class="cell"><div class="id-label">NATIONALITÉ</div><div class="value">Américaine</div></div>
<div class="cell"><div class="id-label">N° DE CITOYEN</div><div class="value mono">@Documents.CitizenId( Player.SteamId )</div></div>
</div>
</div>
</div>
<div class="foot">
<div class="cell"><div class="id-label">DÉLIVRÉE LE</div><div class="value">@Format.Date( ShownIssued )</div></div>
<div class="cell"><div class="id-label">EXPIRE LE</div><div class="value">@Documents.PlusYears( ShownIssued, Documents.IdValidYears )</div></div>
<div class="seal"><i>verified</i></div>
</div>
}
else
{
<div class="back">
<div class="barcode">
@for ( var i = 0; i < 46; i++ )
{
<div class="bar" style="width: @(Bar( i ))px"></div>
}
</div>
<div class="back-id">@($"{(Documents.CitizenId( Player.SteamId ))} · {(Player.PhoneNumber)}")</div>
<div class="back-text">Cette carte est la propriété de l'État de New Horizon. Si vous la trouvez, rapportez-la à un commissariat d'Union City.</div>
</div>
}
</root>
@code
{
public RoleplayPlayer Player { get; set; }
public bool Flipped { get; set; }
// Création du personnage : ce que le formulaire dit, avant tout enregistrement.
public string NameOverride { get; set; }
public string BirthOverride { get; set; }
public string SexOverride { get; set; }
public string AppearanceOverride { get; set; }
string ShownName => NameOverride ?? Player?.RpName;
string ShownBirth => BirthOverride ?? Player?.BirthDate;
string ShownSex => SexOverride ?? Player?.Sex;
string ShownAppearance => AppearanceOverride ?? Player?.AppearanceJson;
/// <summary>Une carte faite à la création est délivrée aujourd'hui.</summary>
string ShownIssued => NameOverride is not null ? DateTime.UtcNow.ToString( "yyyy-MM-dd" ) : Player?.IdIssued;
ScenePanel Photo { get; set; }
readonly Preview3D photo = new() { TurnSpeed = 0, HeadDistance = 20f, HeadHeight = 67f, FaceOnly = true };
/// <summary>Largeur des barres du code-barres, tirée du numéro de citoyen : la même pour une même personne.</summary>
int Bar( int i ) => 1 + (Documents.CitizenId( Player?.SteamId ?? 0 )[i % 9] + i * 7) % 3;
public override void Tick()
{
base.Tick();
if ( Player is null || Flipped || Photo is null )
return;
photo.Attach( Photo );
photo.ShowCharacter( ShownAppearance, ShownSex, headOnly: true );
photo.Tick();
}
protected override int BuildHash() => HashCode.Combine( ShownName, ShownBirth, ShownSex, ShownIssued, Flipped );
}