using System; using System.Collections.Generic; using System.Linq; using LuckerGame.Enums; using LuckerGame.Events; using Sandbox; using Sandbox.UI; namespace LuckerGame.Entities; /// /// Manages rounds. Starting, stopping, triggering minigames from the manager, etc /// public partial class RoundManager : Entity { /// /// The minigame manager we should be using to manage minigames /// private MinigameManager MinigameManager { get; set; } /// /// This percentage of the lobby must be ready to start the countdown for round start /// private const float RequiredReadyPercent = .5f; /// /// The number of seconds from the timer starting before the round starts /// private const float RoundStartCountdownSeconds = 5f; /// /// The state of the current round /// [Net] public RoundState RoundState { get; private set; } #region Countdown State /// /// How long since we started counting down to game start. Only useful if in the StartCountdown state. /// [Net] public TimeSince TimeSinceCountdownStarted { get; set; } /// /// The number of seconds left in the countdown. Only useful if in the StartCountdown state. /// public int SecondsLeftInCountdown => (int)Math.Ceiling( RoundStartCountdownSeconds - TimeSinceCountdownStarted ); #endregion #region In Progress State /// /// The number of minigames that should be played per round, settable via a convar /// [ConVar.Replicated("lucker_minigames_per_round")] private static int MinigamesPerRound { get; set; } /// /// The number of minigames left in the current round /// public int MinigamesLeftInRound { get; set; } /// /// The luckers playing in the current round /// private List Luckers { get; set; } #endregion /// public override void Spawn() { base.Spawn(); RoundState = RoundState.NotStarted; MinigameManager = new MinigameManager(); } /// /// Fires once per server tick /// [GameEvent.Tick.Server] public void Tick() { if ( RoundState == RoundState.StartCountdown && TimeSinceCountdownStarted > RoundStartCountdownSeconds ) { Log.Info( "Starting round" ); StartRound(); } if ( RoundState == RoundState.InProgress ) { var ended = MinigameManager.Tick(); if ( ended ) { MinigamesLeftInRound--; if ( MinigamesLeftInRound > 0 ) { MinigameManager.StartMinigame( Luckers ); } else { RoundState = RoundState.NotStarted; } } } } /// /// Is triggered whenever a lucker readies up or readies down /// /// the lucker that readied up /// the lucker's ready state [LuckerEvent.LuckerReady] public void HandleLuckerReady( Lucker readyLucker, bool ready ) { if ( RoundState != RoundState.NotStarted && RoundState != RoundState.StartCountdown ) { return; } Log.Info( $"{readyLucker.Client.Name} set ready to {ready}" ); var message = $"{readyLucker.Client.Name} is {(ready ? "now ready." : "no longer ready.")}"; ChatBox.AddInformation( To.Everyone, message ); var luckers = All.OfType().ToList(); var readiedCount = luckers.Count( lucker => lucker.Ready ); var totalCount = luckers.Count; if ( (float)readiedCount / totalCount > RequiredReadyPercent && RoundState == RoundState.NotStarted ) { Log.Info( "Countdown started" ); RoundState = RoundState.StartCountdown; TimeSinceCountdownStarted = 0; } else if ( (float)readiedCount / totalCount <= RequiredReadyPercent && RoundState == RoundState.StartCountdown ) { Log.Info( "Countdown ended" ); RoundState = RoundState.NotStarted; } } private void StartRound( string minigameName = null ) { if ( RoundState == RoundState.InProgress ) { Log.Warning( "Attempted to start round while one was in progress" ); return; } RoundState = RoundState.InProgress; Luckers = All.OfType().ToList(); Luckers.ForEach( lucker => { lucker.Ready = false; } ); MinigamesLeftInRound = MinigamesPerRound; MinigameManager.StartMinigame( Luckers, minigameName ); } [ConCmd.Server( "start_round" )] public static void ForceStart( string minigameName = null ) { Entity.All.OfType().FirstOrDefault()?.StartRound( minigameName ); } }