The wallet UI panel, opened with the K key. Shows the local player's ID card, driving license, job badge, bank card and cash in a two-leaf leather wallet, with a detail pane of actions such as showing the ID to nearby players or flipping the card. Also renders another player's ID card for 10 seconds when they present it.
@using Sandbox;
@using Sandbox.UI;
@namespace HorizonRP
@inherits PanelComponent
@*
Le portefeuille (touche K) : un portefeuille de cuir ouvert sur deux volets.
Documents à gauche (carte d'identité, permis, badge de métier), cartes à droite
(carte HZ BANK, espèces). On clique une pièce : elle passe au premier plan, avec
ses actions à droite (montrer aux joueurs proches, retourner, ranger).
Quand un autre joueur vous montre sa carte, elle s'affiche quelques secondes.
*@
<root>
@if ( Presented is { } other && sincePresented < PresentSeconds )
{
<div class="presented">
<div class="presented-title"><i>badge</i> @($"{(other.RpName)} vous montre sa carte d'identité")</div>
<IdCard Player=@other></IdCard>
</div>
}
@if ( IsOpen && Me is not null )
{
<div class="wallet-backdrop">
<div class="wallet">
@* Les billets dépassent du compartiment, derrière les deux volets. *@
<div class="bills-peek" onclick=@(() => Select( "especes" ))>
<div class="bill b1"><span>100</span></div>
<div class="bill b2"><span>50</span></div>
<div class="bill b3"><span>20</span></div>
</div>
<div class="leaf left">
<div class="stitch"></div>
<div class="leaf-title">DOCUMENTS</div>
@* La carte d'identité derrière sa fenêtre transparente. *@
<div class="window @(Selected == "id" ? "selected" : "")" onclick=@(() => Select( "id" ))>
<IdCard Player=@Me Flipped=@(Selected == "id" && Flipped)></IdCard>
<div class="glare"></div>
</div>
@* Les autres papiers, glissés dans des fentes : on n'en voit que le haut. *@
<div class="slot paper">
<div class="peek license">
<div class="peek-left">@Documents.State</div>
<div class="peek-right">PERMIS DE CONDUIRE</div>
</div>
<div class="lip"></div>
</div>
@if ( Documents.BadgeOf( Me.JobId ) is { } badge )
{
<div class="slot paper">
<div class="peek badge">
<div class="peek-left">@badge.Agency</div>
<div class="peek-right">@badge.Title</div>
</div>
<div class="lip"></div>
</div>
}
</div>
<div class="spine"></div>
<div class="leaf right">
<div class="stitch"></div>
<div class="leaf-title">CARTES</div>
@* La carte HZ BANK dans sa fente : choisie, elle en sort. *@
<div class="card-slot @(Selected == "carte" ? "out" : "")">
<div class="bank-card @(Selected == "carte" && Flipped ? "flipped" : "")" onclick=@(() => Select( "carte" ))>
@if ( Selected == "carte" && Flipped )
{
<div class="stripe"></div>
<div class="signature-row">
<div class="signature">@Me.RpName</div>
<div class="cvv">@Documents.Cvv( Me.SteamId )</div>
</div>
<div class="balance">@($"Solde : {(Format.Money( Me.Bank ))}")</div>
<div class="card-legal">@($"Cette carte reste la propriété de {(Documents.BankName)}.")</div>
}
else
{
<div class="card-top">
<div class="bank-name">@Documents.BankName</div>
<div class="default">PAR DÉFAUT</div>
</div>
<div class="card-sub">COMPTE PERSONNEL</div>
<div class="chip-row"><div class="chip"></div><i>contactless</i></div>
<div class="card-number">@Documents.CardNumber( Me.SteamId )</div>
<div class="card-bottom">
<div class="cell"><div class="card-label">TITULAIRE</div><div class="card-value">@Me.RpName.ToUpperInvariant()</div></div>
<div class="cell"><div class="card-label">EXPIRE FIN</div><div class="card-value">@Documents.ValidThru( Me.IdIssued )</div></div>
<div class="network"><div class="circle a"></div><div class="circle b"></div></div>
</div>
}
</div>
<div class="lip"></div>
</div>
@* Deux fentes vides, pour l'allure d'un vrai porte-cartes. *@
<div class="slot empty"><div class="lip"></div></div>
<div class="slot empty"><div class="lip"></div></div>
<div class="cash" onclick=@(() => Select( "especes" ))>
<i>payments</i>
<div class="cash-amount">
<div class="card-label">ESPÈCES</div>
<div class="cash-value">@Format.Money( Me.Wallet )</div>
</div>
</div>
</div>
<div class="detail">
@if ( Selected == "id" )
{
<div class="detail-kind">DOCUMENT</div>
<div class="detail-title">Carte d'identité</div>
<div class="detail-line"><span>Né(e) le</span><b>@Format.Date( Me.BirthDate )</b></div>
<div class="detail-line"><span>N° de citoyen</span><b>@Documents.CitizenId( Me.SteamId )</b></div>
<div class="detail-line"><span>Expire le</span><b>@Documents.PlusYears( Me.IdIssued, Documents.IdValidYears )</b></div>
<div class="action gold" onclick=@(() => Me.RequestShowId())><i>visibility</i> Montrer aux joueurs proches</div>
<div class="action" onclick=@(() => Flipped = !Flipped)><i>flip</i> Retourner</div>
<div class="action" onclick=@(() => Select( null ))><i>undo</i> Ranger</div>
}
else if ( Selected == "carte" )
{
<div class="detail-kind">COMPTE PERSONNEL</div>
<div class="detail-title">@($"{(Documents.BankName)} Classic")</div>
<div class="detail-line"><span>Solde</span><b class="money">@Format.Money( Me.Bank )</b></div>
<div class="detail-line"><span>Titulaire</span><b>@Me.RpName</b></div>
<div class="detail-line"><span>Valide jusqu'au</span><b>@Documents.ValidThru( Me.IdIssued )</b></div>
<div class="action" onclick=@(() => Flipped = !Flipped)><i>flip</i> Retourner</div>
<div class="action" onclick=@(() => Select( null ))><i>undo</i> Ranger</div>
}
else if ( Selected == "especes" )
{
<div class="detail-kind">ESPÈCES</div>
<div class="detail-title">@Format.Money( Me.Wallet )</div>
<div class="detail-text">L'argent liquide part avec vous. Déposez-le à la banque (F4, ou un distributeur) pour le mettre à l'abri.</div>
<div class="action" onclick=@(() => Select( null ))><i>undo</i> Ranger</div>
}
else
{
<div class="detail-kind">PORTEFEUILLE</div>
<div class="detail-title">@Me.RpName</div>
<div class="detail-text">Cliquez une carte ou un document pour le sortir.</div>
}
<div class="hint-keys"><span class="key">K</span> fermer</div>
</div>
</div>
</div>
}
</root>
@code
{
public const float PresentSeconds = 10f;
static RoleplayPlayer Presented;
static RealTimeSince sincePresented;
/// <summary>Un autre joueur nous montre sa carte d'identité (RPC de l'hôte).</summary>
public static void Present( RoleplayPlayer player )
{
Presented = player;
sincePresented = 0;
}
public bool IsOpen { get; private set; }
string Selected { get; set; }
bool Flipped { get; set; }
RoleplayPlayer Me => RoleplayPlayer.Local;
protected override void OnUpdate()
{
if ( Me is null || Me.NeedsCharacter )
{
if ( IsOpen ) SetOpen( false );
return;
}
// Échap referme ce menu (et ne laisse pas s'ouvrir le menu pause en même temps).
if ( IsOpen && Input.EscapePressed )
{
Input.EscapePressed = false;
SetOpen( false );
return;
}
if ( Input.Pressed( "Wallet" ) )
SetOpen( !IsOpen );
}
void SetOpen( bool open )
{
IsOpen = open;
Selected = null;
Flipped = false;
UiLock.Set( "portefeuille", open );
}
protected override void OnDisabled() => UiLock.Set( "portefeuille", false );
void Select( string what )
{
if ( Selected != what )
Flipped = false;
Selected = what;
}
protected override int BuildHash() => HashCode.Combine(
HashCode.Combine( IsOpen, Selected, Flipped ),
HashCode.Combine( Me?.Bank, Me?.Wallet, Me?.JobId, Me?.RpName ),
Presented?.SteamId, sincePresented < PresentSeconds );
}