UI/MainMenu.razor
@namespace Sandbox.UI
@using System;
@using System.Collections.Generic;
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
<root class="@( _isMenuVisible ? "menu-active" : "hidden" )">
<style>
@@import "theme.scss";
MainMenu {
position: absolute;
inset: 0;
display: none;
pointer-events: none;
font-family: sans-serif;
&.menu-active {
display: flex;
pointer-events: all;
background: linear-gradient(90deg, rgba(6, 8, 11, 0.80) 0%, rgba(6, 8, 11, 0.50) 45%, rgba(0, 0, 0, 0.05) 100%);
}
}
.menu-left-sidebar {
width: 540px;
height: 100%;
padding: 80px 64px;
flex-direction: column;
justify-content: center;
gap: 28px;
}
.game-logo {
max-width: 400px;
max-height: 140px;
margin-bottom: 8px;
}
.logo-placeholder {
font-size: 46px;
font-weight: 900;
color: #ffd57e;
letter-spacing: 8px;
text-transform: uppercase;
border-bottom: 2px solid rgba(229, 169, 60, 0.5);
padding-bottom: 14px;
margin-bottom: 12px;
text-shadow: 0 0 24px rgba(229, 169, 60, 0.45);
}
.logo-tagline {
font-size: 13px;
font-weight: 700;
color: #94a3b8;
letter-spacing: 4px;
text-transform: uppercase;
margin-top: -18px;
margin-bottom: 16px;
}
.nav-buttons {
flex-direction: column;
gap: 16px;
width: 340px;
}
.menu-modal {
position: absolute;
top: 25%;
left: 580px;
width: 480px;
background-color: rgba(12, 15, 21, 0.88);
border: 1px solid rgba(229, 169, 60, 0.5);
border-radius: 4px;
padding: 28px;
flex-direction: column;
gap: 18px;
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.85);
}
.modal-title {
font-size: 16px;
font-weight: 900;
color: #ffd57e;
letter-spacing: 2px;
text-transform: uppercase;
border-bottom: 1px solid rgba(229, 169, 60, 0.2);
padding-bottom: 10px;
}
.config-row {
flex-direction: row;
justify-content: space-between;
align-items: center;
color: #cbd5e1;
font-size: 13px;
font-weight: 700;
letter-spacing: 0.5px;
}
.config-input {
width: 90px;
height: 36px;
background-color: rgba(255, 255, 255, 0.07);
border: 1px solid rgba(229, 169, 60, 0.35);
border-radius: 2px;
color: #ffffff;
font-family: monospace;
font-size: 14px;
padding: 4px 8px;
text-align: center;
}
.options-desc {
font-size: 12px;
color: #94a3b8;
line-height: 18px;
}
.status-feedback {
font-size: 12px;
font-weight: 800;
color: #22c55e;
letter-spacing: 1px;
text-transform: uppercase;
}
.btn-danger {
border-color: #ef4444;
background: linear-gradient(180deg, rgba(60, 18, 18, 0.7) 0%, rgba(35, 10, 10, 0.85) 100%);
color: #fca5a5;
&:hover {
border-color: #f87171;
background: linear-gradient(180deg, rgba(120, 28, 28, 0.85) 0%, rgba(70, 15, 15, 0.95) 100%);
color: #ffffff;
}
}
</style>
<div class="menu-left-sidebar">
@if ( !string.IsNullOrEmpty( LogoTexturePath ) && FileSystem.Mounted.FileExists( LogoTexturePath ) )
{
<img class="game-logo" src="@LogoTexturePath" />
}
else
{
<span class="logo-placeholder">MORITURI</span>
<span class="logo-tagline">Blood & Arena Combat</span>
}
<div class="nav-buttons">
<button class="btn-roman" @onclick=@StartCampaign>Campaign (7 Days)</button>
<button class="btn-roman" @onclick=@ToggleFreePlayModal>Free Play</button>
<button class="btn-roman" @onclick=@ToggleOptionsModal>Options</button>
<button class="btn-roman" style="opacity: 0.5;" @onclick=@OpenAchievements>Achievements</button>
</div>
</div>
@* MODALE : FREE PLAY *@
@if ( _showFreePlayModal )
{
<div class="menu-modal">
<span class="modal-title">Custom Arena Settings</span>
<div class="config-row">
<span>Total Combatants</span>
<TextEntry class="config-input" Value:bind=@_freePlayTotalCombatants />
</div>
<div class="config-row">
<span>Max Concurrent</span>
<TextEntry class="config-input" Value:bind=@_freePlayMaxConcurrent />
</div>
<div class="config-row">
<span>Duration (Seconds)</span>
<TextEntry class="config-input" Value:bind=@_freePlayDuration />
</div>
<div style="flex-direction: row; gap: 14px; margin-top: 14px;">
<button class="btn-roman" style="flex-grow: 1;" @onclick=@LaunchFreePlay>Enter Arena</button>
<button class="btn-roman" style="width: 110px; border-color: #64748b;" @onclick=@ToggleFreePlayModal>Cancel</button>
</div>
</div>
}
@* MODALE : OPTIONS *@
@if ( _showOptionsModal )
{
<div class="menu-modal">
<span class="modal-title">Options & Data</span>
<span class="options-desc">
Resetting your campaign will permanently erase current round progress, acquired fans, and rival gladiator profiles.
</span>
<button class="btn-roman btn-danger" @onclick=@ResetSaveData>Reset Saved Progression</button>
@if ( !string.IsNullOrEmpty( _saveFeedbackText ) )
{
<span class="status-feedback">@_saveFeedbackText</span>
}
<div style="flex-direction: row; justify-content: flex-end; margin-top: 12px;">
<button class="btn-roman" style="width: 120px; border-color: #64748b;" @onclick=@ToggleOptionsModal>Close</button>
</div>
</div>
}
</root>
@code {
[Property, Title( "Logo Texture Path (PNG)" )]
public string LogoTexturePath { get; set; } = "/ui/logo_morituri.png";
private bool _isMenuVisible = true;
private bool _showFreePlayModal = false;
private bool _showOptionsModal = false;
private string _saveFeedbackText = "";
private string _freePlayTotalCombatants = "16";
private string _freePlayMaxConcurrent = "4";
private string _freePlayDuration = "300";
protected override void OnStart()
{
_isMenuVisible = true;
UIStateManager.RequestFocus( this );
}
protected override void OnDestroy()
{
UIStateManager.ReleaseFocus( this );
}
private void StartCampaign()
{
_isMenuVisible = false;
_showFreePlayModal = false;
_showOptionsModal = false;
UIStateManager.ClearAllFocus();
Log.Info( "⚔️ [MENU] Campaign started. Controls unlocked." );
}
private void ToggleFreePlayModal()
{
_showFreePlayModal = !_showFreePlayModal;
if ( _showFreePlayModal ) _showOptionsModal = false;
_saveFeedbackText = "";
}
private void ToggleOptionsModal()
{
_showOptionsModal = !_showOptionsModal;
if ( _showOptionsModal ) _showFreePlayModal = false;
_saveFeedbackText = "";
}
private void ResetSaveData()
{
SaveManager.ClearSave();
_saveFeedbackText = "Progression successfully erased!";
GameManager.Instance?.ResetCampaignProgression();
Log.Info( "🗑️ [SAVE] Campaign progression has been reset from main menu." );
}
private void LaunchFreePlay()
{
int.TryParse( _freePlayTotalCombatants, out var total );
int.TryParse( _freePlayMaxConcurrent, out var concurrent );
float.TryParse( _freePlayDuration, out var dur );
var customRound = new RoundConfig
{
RoundTitle = "Custom Arena",
TotalCombatants = Math.Max( 1, total ),
MaxConcurrentFighters = Math.Max( 1, concurrent ),
RoundDuration = Math.Max( 30f, dur )
};
_isMenuVisible = false;
_showFreePlayModal = false;
_showOptionsModal = false;
UIStateManager.ClearAllFocus();
GameManager.Instance?.StartCustomRound( customRound );
}
private void OpenAchievements()
{
Log.Info( "🏛️ [MENU] Achievements coming soon!" );
}
protected override int BuildHash()
{
return HashCode.Combine( _isMenuVisible, _showFreePlayModal, _showOptionsModal, _saveFeedbackText );
}
}