A Razor UI component for the lobby menu. It renders coin display, player slots/nametags, various panels (quest, shop, loadout, perks, leaderboard), and play/quit buttons, and handles input for controller/keyboard to start or quit the game and toggle subpanels.
@namespace Sandbox
@using Sandbox;
@using Sandbox.UI;
@using System;
@using System.Linq;
@inherits Panel
@attribute [StyleSheet("LobbyMenu.razor.scss")]
<root>
@if ( !Manager.HideProgressionSystem )
{
<div class="coin_display">
<div class="coin_display_icon"></div>
<label class="coin_display_amount">@ProgressManager.GetCoins()</label>
</div>
}
@foreach( var slot in Game.ActiveScene.GetAllComponents<LobbyPlayerSlot>() )
{
var player = slot.OccupyingPlayer;
int left = 0;
int bottom = 0;
switch(slot.SlotIndex)
{
case 0:
left = 50;
bottom = 40;
break;
case 1:
left = 40;
bottom = 65;
break;
case 2:
left = 60;
bottom = 65;
break;
}
@if(player is not null)
{
var name = player.Network.Owner.DisplayName;
var steamId = player.Network.Owner.SteamId;
<LobbyNametagPanel style="left: @(left)%; bottom: @(bottom)px; transform: translate(-50%, 0%);" PlayerInfo=@(new PlayerInfo(name, steamId, level: -1)) />
}
else
{
<LobbySlotPanel Index=@(slot.SlotIndex) style="left: @(left)%; bottom: @(bottom)px; transform: translate(-50%, 0%);" />
}
}
@if(Manager.Instance.ShowQuestPanel)
{
<QuestPanel />
}
else if(Manager.Instance.ShowShopPanel)
{
<ShopPanel />
}
else if(Manager.Instance.ShowLoadoutPanel)
{
<LoadoutPanel />
}
else if(Manager.Instance.ShowPerkUnlockPanel)
{
<PerkUnlockPanel />
}
else if(Manager.Instance.PlayerProfileToShow != null)
{
<PlayerProfilePanel />
}
else if(Manager.Instance.RunEntryToShow != null)
{
<LeaderboardRunInfoPanel />
}
else
{
<div class="upper_right">
<DifficultyPanel />
<LeaderboardPanel style="position: relative; top: 0px; right: 0px; width: 500px;" [email protected] IsOnMainMenu=@true />
</div>
@if ( !Manager.HideProgressionSystem )
{
<div class="top_left_buttons">
<button class="quest_button" onclick=@(() => ClickQuestButton())>Quests
@{
var questReadyCount = ProgressManager.Quests.Count(q => ProgressManager.IsQuestReadyToCollect(q.Id))
+ ProgressManager.Achievements.Count(a => ProgressManager.IsAchievementUnlocked(a.Name) && !ProgressManager.IsAchievementClaimed(a.Name));
}
@if(questReadyCount > 0)
{
<div class="quest_badge">@questReadyCount</div>
}
</button>
<button class="shop_button" onclick=@(() => ClickShopButton())>Shop</button>
<button class="loadout_button" onclick=@(() => ClickLoadoutButton())>Loadout</button>
<button class="perks_button" onclick=@(() => ClickPerksButton())>Perks</button>
</div>
}
<div class="content">
@if(Networking.IsHost && Scene.GetAllComponents<Player>().Count() > 0)
{
<button class="play_button @(Input.UsingController ? "controller" : "") @(_playActivated ? "ctrl-activated" : _playHeld ? "ctrl-held" : "")" onclick=@(() => Play())>
</button>
}
else
{
<button class="play_button_client"></button>
}
<button class="quit_button @(Input.UsingController ? "controller" : "") @(_quitActivated ? "ctrl-activated" : _quitHeld ? "ctrl-held" : "")" onclick=@(() => Quit())>
</button>
</div>
// hack to make player levels update properly when viewing leaderboard
// todo: unnecessary unless player levels return
@* if(Manager.Instance.SkipShowingLeaderboardFrames > 0)
{
Manager.Instance.SkipShowingLeaderboardFrames--;
}
else
{
<LeaderboardPanel [email protected]></LeaderboardPanel>
} *@
}
@if(!string.IsNullOrEmpty(Manager.Instance.LobbyHoveredPlayerName ))
{
<PlayerTooltip [email protected] ShowIcon=@false />
}
@* <div class="blank"></div> *@
</root>
@code
{
public void Play()
{
if (!Networking.IsHost)
return;
StartGame();
}
async void StartGame()
{
Manager.Instance.FadeRpc(fadeIn: false);
await Task.Frame();
Manager.Instance.SetGameState(GameState.Playing);
}
public void Quit()
{
Game.Close();
}
bool _playHeld;
bool _playActivated;
bool _quitHeld;
bool _quitActivated;
public override void Tick()
{
base.Tick();
if (!Input.UsingController)
{
_playHeld = false;
_playActivated = false;
_quitHeld = false;
_quitActivated = false;
if (Input.Pressed("banish")) Quit();
return;
}
if (_playActivated)
{
_playActivated = false;
Play();
return;
}
if (_quitActivated)
{
_quitActivated = false;
Quit();
return;
}
bool playDown = Input.Down("R");
if (_playHeld && !playDown)
{
_playHeld = false;
_playActivated = true;
Manager.Instance.PlaySfxUI("click", pitch: 1.15f, volume: 0.75f);
}
else
{
if (!_playHeld && playDown)
Manager.Instance.PlaySfxUI("click", pitch: 0.85f, volume: 0.6f);
_playHeld = playDown;
}
bool quitDown = Input.Down("banish");
if (_quitHeld && !quitDown)
{
_quitHeld = false;
_quitActivated = true;
Manager.Instance.PlaySfxUI("click", pitch: 1.15f, volume: 0.75f);
}
else
{
if (!_quitHeld && quitDown)
Manager.Instance.PlaySfxUI("click", pitch: 0.85f, volume: 0.6f);
_quitHeld = quitDown;
}
}
protected override int BuildHash()
{
var leaderboardPerkHash = Manager.Instance.RunEntryToShow?.GetHashCode() ?? 0;
var showHash = System.HashCode.Combine(
Manager.Instance.ShowQuestPanel,
Manager.Instance.ShowShopPanel,
Manager.Instance.ShowLoadoutPanel,
Manager.Instance.ShowPerkUnlockPanel
);
return System.HashCode.Combine(
Manager.Instance.IsEscMenuOpen,
leaderboardPerkHash,
showHash,
Input.UsingController,
ProgressManager.StateVersion,
Time.Now // todo: ?
);
}
void ClickQuestButton()
{
Manager.Instance.ShowQuestPanel = true;
}
void ClickShopButton()
{
Manager.Instance.ShowShopPanel = true;
}
void ClickLoadoutButton()
{
Manager.Instance.ShowLoadoutPanel = true;
}
void ClickPerksButton()
{
Manager.Instance.ShowPerkUnlockPanel = true;
}
}