Loading overlay panel for the Horizon RP gamemode. Shows a spinner, the current load step and rotating tips until the local player's profile is loaded, and plays looping menu music until the player enters the world.
@using Sandbox;
@using Sandbox.UI;
@namespace HorizonRP
@inherits PanelComponent
@*
L'écran d'arrivée d'Horizon RP. Le chargement de la carte, lui, est dessiné
par s&box (on ne peut qu'y mettre une image, à la publication du paquet) ;
celui-ci prend le relais dès que le jeu tourne et jusqu'à ce que le profil du
joueur soit chargé : même image, l'étape en cours et des astuces qui défilent.
La musique du menu (sounds/menu_music.mp3) joue pendant l'arrivée et la
création du personnage, puis s'éteint en fondu quand on entre en ville.
*@
<root class="@(Visible ? "" : "gone")">
@if ( Visible || sinceHidden < 0.6f )
{
<div class="overlay @(Visible ? "" : "fading")">
<div class="bottom">
<div class="spinner"></div>
<div class="step">@Step</div>
<div class="tip"><span class="tip-label">ASTUCE</span> @Tips[(int)(sinceShown / 5f) % Tips.Length]</div>
</div>
</div>
}
</root>
@code
{
static readonly string[] Tips =
{
"La flèche ↑ ouvre votre téléphone : appelez, envoyez des SMS, faites un virement.",
"I ouvre l'inventaire ; les cases 1 à 5 s'utilisent directement aux touches 1 à 5.",
"K ouvre votre portefeuille : montrez votre carte d'identité aux joueurs proches.",
"P sur une porte : achetez-la, verrouillez-la, donnez la clé à vos amis.",
"Au garage (touche E), la concession vend des véhicules ; L les verrouille.",
"F4 : choisissez un métier. Le salaire tombe toutes les cinq minutes.",
"Pensez à manger : la faim fait baisser la vie quand elle est à zéro.",
"Un souci ? Le téléphone a une application « Signaler » qui prévient le staff.",
};
RealTimeSince sinceShown;
RealTimeSince sinceHidden;
bool wasVisible = true;
RoleplayPlayer Me => RoleplayPlayer.Local;
/// <summary>Tant que le joueur n'existe pas, ou que son profil n'est pas encore arrivé.</summary>
bool Visible => Me is null || (!Me.NeedsCharacter && string.IsNullOrEmpty( Me.AppearanceJson ));
string Step => Me is null ? "Arrivée à Union City…" : "Chargement de votre profil…";
protected override void OnStart() => sinceShown = 0;
protected override void OnUpdate()
{
if ( wasVisible && !Visible )
sinceHidden = 0;
wasVisible = Visible;
UpdateMusic();
}
protected override void OnDestroy() => music?.Stop( 0.5f );
// Musique du menu
const string MusicFile = "sounds/menu_music.mp3";
const float MusicVolume = 0.45f;
SoundHandle music;
bool musicDone;
/// <summary>Pendant l'arrivée, puis la création du personnage (première connexion).</summary>
bool MusicWanted => Visible || (Me?.NeedsCharacter ?? false);
void UpdateMusic()
{
if ( musicDone || Application.IsDedicatedServer )
return;
if ( !MusicWanted )
{
// Une fois en ville, elle ne revient plus de la session.
music?.Stop( 3f );
music = null;
musicDone = true;
return;
}
// En boucle : relancée quand le morceau se termine.
if ( music is null || music.IsStopped )
{
music = Sound.PlayFile( SoundFile.Load( MusicFile ), MusicVolume );
if ( music is null )
{
// Fichier absent ou illisible : on n'insiste pas à chaque image.
musicDone = true;
return;
}
music.ListenLocal = true;
music.Position = Vector3.Forward * 10f;
}
}
protected override int BuildHash() => HashCode.Combine( Visible, Step, (int)(sinceShown / 5f), sinceHidden < 0.6f );
}