using System.Collections.Generic; using System.Linq; using System.Text; using Content.Client.Arcade.UI; using Content.Client.Resources; using Content.Shared.Arcade; using Content.Shared.Input; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.Utility; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Arcade { public class BlockGameMenu : SS14Window { private static readonly Color OverlayBackgroundColor = new(74,74,81,180); private static readonly Color OverlayShadowColor = new(0,0,0,83); private static readonly Vector2 BlockSize = new(15,15); private readonly BlockGameBoundUserInterface _owner; private readonly PanelContainer _mainPanel; private BoxContainer _gameRootContainer; private GridContainer _gameGrid = default!; private GridContainer _nextBlockGrid = default!; private GridContainer _holdBlockGrid = default!; private readonly Label _pointsLabel; private readonly Label _levelLabel; private readonly Button _pauseButton; private readonly PanelContainer _menuRootContainer; private readonly Button _unpauseButton; private readonly Control _unpauseButtonMargin; private readonly Button _newGameButton; private readonly Button _scoreBoardButton; private readonly PanelContainer _gameOverRootContainer; private readonly Label _finalScoreLabel; private readonly Button _finalNewGameButton; private readonly PanelContainer _highscoresRootContainer; private readonly Label _localHighscoresLabel; private readonly Label _globalHighscoresLabel; private readonly Button _highscoreBackButton; private bool _isPlayer = false; private bool _gameOver = false; public BlockGameMenu(BlockGameBoundUserInterface owner) { Title = Loc.GetString("blockgame-menu-title"); _owner = owner; MinSize = SetSize = (410, 490); var resourceCache = IoCManager.Resolve(); var backgroundTexture = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); _mainPanel = new PanelContainer(); #region Game Menu // building the game container _gameRootContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical }; _levelLabel = new Label { Align = Label.AlignMode.Center, HorizontalExpand = true }; _gameRootContainer.AddChild(_levelLabel); _gameRootContainer.AddChild(new Control { MinSize = new Vector2(1,5) }); _pointsLabel = new Label { Align = Label.AlignMode.Center, HorizontalExpand = true }; _gameRootContainer.AddChild(_pointsLabel); _gameRootContainer.AddChild(new Control { MinSize = new Vector2(1,10) }); var gameBox = new BoxContainer { Orientation = LayoutOrientation.Horizontal }; gameBox.AddChild(SetupHoldBox(backgroundTexture)); gameBox.AddChild(new Control { MinSize = new Vector2(10,1) }); gameBox.AddChild(SetupGameGrid(backgroundTexture)); gameBox.AddChild(new Control { MinSize = new Vector2(10,1) }); gameBox.AddChild(SetupNextBox(backgroundTexture)); _gameRootContainer.AddChild(gameBox); _gameRootContainer.AddChild(new Control { MinSize = new Vector2(1,10) }); _pauseButton = new Button { Text = Loc.GetString("blockgame-menu-button-pause"), TextAlign = Label.AlignMode.Center }; _pauseButton.OnPressed += (e) => TryPause(); _gameRootContainer.AddChild(_pauseButton); #endregion _mainPanel.AddChild(_gameRootContainer); #region Pause Menu var pauseRootBack = new StyleBoxTexture { Texture = backgroundTexture, Modulate = OverlayShadowColor }; pauseRootBack.SetPatchMargin(StyleBox.Margin.All, 10); _menuRootContainer = new PanelContainer { PanelOverride = pauseRootBack, VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center }; var pauseInnerBack = new StyleBoxTexture { Texture = backgroundTexture, Modulate = OverlayBackgroundColor }; pauseInnerBack.SetPatchMargin(StyleBox.Margin.All, 10); var pauseMenuInnerPanel = new PanelContainer { PanelOverride = pauseInnerBack, VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center }; _menuRootContainer.AddChild(pauseMenuInnerPanel); var pauseMenuContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center }; _newGameButton = new Button { Text = Loc.GetString("blockgame-menu-button-new-game"), TextAlign = Label.AlignMode.Center }; _newGameButton.OnPressed += (e) => { _owner.SendAction(BlockGamePlayerAction.NewGame); }; pauseMenuContainer.AddChild(_newGameButton); pauseMenuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); _scoreBoardButton = new Button { Text = Loc.GetString("blockgame-menu-button-scoreboard"), TextAlign = Label.AlignMode.Center }; _scoreBoardButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.ShowHighscores); pauseMenuContainer.AddChild(_scoreBoardButton); _unpauseButtonMargin = new Control {MinSize = new Vector2(1, 10), Visible = false}; pauseMenuContainer.AddChild(_unpauseButtonMargin); _unpauseButton = new Button { Text = Loc.GetString("blockgame-menu-button-unpause"), TextAlign = Label.AlignMode.Center, Visible = false }; _unpauseButton.OnPressed += (e) => { _owner.SendAction(BlockGamePlayerAction.Unpause); }; pauseMenuContainer.AddChild(_unpauseButton); pauseMenuInnerPanel.AddChild(pauseMenuContainer); #endregion #region Gameover Screen var gameOverRootBack = new StyleBoxTexture { Texture = backgroundTexture, Modulate = OverlayShadowColor }; gameOverRootBack.SetPatchMargin(StyleBox.Margin.All, 10); _gameOverRootContainer = new PanelContainer { PanelOverride = gameOverRootBack, VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center }; var gameOverInnerBack = new StyleBoxTexture { Texture = backgroundTexture, Modulate = OverlayBackgroundColor }; gameOverInnerBack.SetPatchMargin(StyleBox.Margin.All, 10); var gameOverMenuInnerPanel = new PanelContainer { PanelOverride = gameOverInnerBack, VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center }; _gameOverRootContainer.AddChild(gameOverMenuInnerPanel); var gameOverMenuContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center }; gameOverMenuContainer.AddChild(new Label{Text = Loc.GetString("blockgame-menu-msg-game-over"),Align = Label.AlignMode.Center}); gameOverMenuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); _finalScoreLabel = new Label{Align = Label.AlignMode.Center}; gameOverMenuContainer.AddChild(_finalScoreLabel); gameOverMenuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); _finalNewGameButton = new Button { Text = Loc.GetString("blockgame-menu-button-new-game"), TextAlign = Label.AlignMode.Center }; _finalNewGameButton.OnPressed += (e) => { _owner.SendAction(BlockGamePlayerAction.NewGame); }; gameOverMenuContainer.AddChild(_finalNewGameButton); gameOverMenuInnerPanel.AddChild(gameOverMenuContainer); #endregion #region High Score Screen var rootBack = new StyleBoxTexture { Texture = backgroundTexture, Modulate = OverlayShadowColor }; rootBack.SetPatchMargin(StyleBox.Margin.All, 10); _highscoresRootContainer = new PanelContainer { PanelOverride = rootBack, VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center }; var c = new Color(OverlayBackgroundColor.R,OverlayBackgroundColor.G,OverlayBackgroundColor.B,220); var innerBack = new StyleBoxTexture { Texture = backgroundTexture, Modulate = c }; innerBack.SetPatchMargin(StyleBox.Margin.All, 10); var menuInnerPanel = new PanelContainer { PanelOverride = innerBack, VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center }; _highscoresRootContainer.AddChild(menuInnerPanel); var menuContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, HorizontalAlignment = HAlignment.Center, VerticalAlignment = VAlignment.Center }; menuContainer.AddChild(new Label{Text = Loc.GetString("blockgame-menu-label-highscores")}); menuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); var highScoreBox = new BoxContainer { Orientation = LayoutOrientation.Horizontal }; _localHighscoresLabel = new Label { Align = Label.AlignMode.Center }; highScoreBox.AddChild(_localHighscoresLabel); highScoreBox.AddChild(new Control{MinSize = new Vector2(40,1)}); _globalHighscoresLabel = new Label { Align = Label.AlignMode.Center }; highScoreBox.AddChild(_globalHighscoresLabel); menuContainer.AddChild(highScoreBox); menuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); _highscoreBackButton = new Button { Text = Loc.GetString("blockgame-menu-button-back"), TextAlign = Label.AlignMode.Center }; _highscoreBackButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.Pause); menuContainer.AddChild(_highscoreBackButton); menuInnerPanel.AddChild(menuContainer); #endregion Contents.AddChild(_mainPanel); CanKeyboardFocus = true; } public void SetUsability(bool isPlayer) { _isPlayer = isPlayer; UpdateUsability(); } private void UpdateUsability() { _pauseButton.Disabled = !_isPlayer; _newGameButton.Disabled = !_isPlayer; _scoreBoardButton.Disabled = !_isPlayer; _unpauseButton.Disabled = !_isPlayer; _finalNewGameButton.Disabled = !_isPlayer; _highscoreBackButton.Disabled = !_isPlayer; } private Control SetupGameGrid(Texture panelTex) { _gameGrid = new GridContainer { Columns = 10, HSeparationOverride = 1, VSeparationOverride = 1 }; UpdateBlocks(new BlockGameBlock[0]); var back = new StyleBoxTexture { Texture = panelTex, Modulate = Color.FromHex("#4a4a51"), }; back.SetPatchMargin(StyleBox.Margin.All, 10); var gamePanel = new PanelContainer { PanelOverride = back, HorizontalExpand = true, SizeFlagsStretchRatio = 60 }; var backgroundPanel = new PanelContainer { PanelOverride = new StyleBoxFlat{BackgroundColor = Color.FromHex("#86868d")} }; backgroundPanel.AddChild(_gameGrid); gamePanel.AddChild(backgroundPanel); return gamePanel; } private Control SetupNextBox(Texture panelTex) { var previewBack = new StyleBoxTexture { Texture = panelTex, Modulate = Color.FromHex("#4a4a51") }; previewBack.SetPatchMargin(StyleBox.Margin.All, 10); var grid = new GridContainer { Columns = 1, HorizontalExpand = true, SizeFlagsStretchRatio = 20 }; var nextBlockPanel = new PanelContainer { PanelOverride = previewBack, MinSize = BlockSize * 6.5f, HorizontalAlignment = HAlignment.Left, VerticalAlignment = VAlignment.Top }; var nextCenterContainer = new CenterContainer(); _nextBlockGrid = new GridContainer { HSeparationOverride = 1, VSeparationOverride = 1 }; nextCenterContainer.AddChild(_nextBlockGrid); nextBlockPanel.AddChild(nextCenterContainer); grid.AddChild(nextBlockPanel); grid.AddChild(new Label{Text = Loc.GetString("blockgame-menu-label-next"), Align = Label.AlignMode.Center}); return grid; } private Control SetupHoldBox(Texture panelTex) { var previewBack = new StyleBoxTexture { Texture = panelTex, Modulate = Color.FromHex("#4a4a51") }; previewBack.SetPatchMargin(StyleBox.Margin.All, 10); var grid = new GridContainer { Columns = 1, HorizontalExpand = true, SizeFlagsStretchRatio = 20 }; var holdBlockPanel = new PanelContainer { PanelOverride = previewBack, MinSize = BlockSize * 6.5f, HorizontalAlignment = HAlignment.Left, VerticalAlignment = VAlignment.Top }; var holdCenterContainer = new CenterContainer(); _holdBlockGrid = new GridContainer { HSeparationOverride = 1, VSeparationOverride = 1 }; holdCenterContainer.AddChild(_holdBlockGrid); holdBlockPanel.AddChild(holdCenterContainer); grid.AddChild(holdBlockPanel); grid.AddChild(new Label{Text = Loc.GetString("blockgame-menu-label-hold"), Align = Label.AlignMode.Center}); return grid; } protected override void KeyboardFocusExited() { if (!IsOpen) return; if(_gameOver) return; TryPause(); } private void TryPause() { _owner.SendAction(BlockGamePlayerAction.Pause); } public void SetStarted() { _gameOver = false; _unpauseButton.Visible = true; _unpauseButtonMargin.Visible = true; } public void SetScreen(BlockGameMessages.BlockGameScreen screen) { if (_gameOver) return; switch (screen) { case BlockGameMessages.BlockGameScreen.Game: GrabKeyboardFocus(); CloseMenus(); _pauseButton.Disabled = !_isPlayer; break; case BlockGameMessages.BlockGameScreen.Pause: //ReleaseKeyboardFocus(); CloseMenus(); _mainPanel.AddChild(_menuRootContainer); _pauseButton.Disabled = true; break; case BlockGameMessages.BlockGameScreen.Gameover: _gameOver = true; _pauseButton.Disabled = true; //ReleaseKeyboardFocus(); CloseMenus(); _mainPanel.AddChild(_gameOverRootContainer); break; case BlockGameMessages.BlockGameScreen.Highscores: //ReleaseKeyboardFocus(); CloseMenus(); _mainPanel.AddChild(_highscoresRootContainer); break; } } private void CloseMenus() { if(_mainPanel.Children.Contains(_menuRootContainer)) _mainPanel.RemoveChild(_menuRootContainer); if(_mainPanel.Children.Contains(_gameOverRootContainer)) _mainPanel.RemoveChild(_gameOverRootContainer); if(_mainPanel.Children.Contains(_highscoresRootContainer)) _mainPanel.RemoveChild(_highscoresRootContainer); } public void SetGameoverInfo(int amount, int? localPlacement, int? globalPlacement) { var globalPlacementText = globalPlacement == null ? "-" : $"#{globalPlacement}"; var localPlacementText = localPlacement == null ? "-" : $"#{localPlacement}"; _finalScoreLabel.Text = Loc.GetString("blockgame-menu-gameover-info", ("global", globalPlacementText), ("local", localPlacementText), ("points", amount)); } public void UpdatePoints(int points) { _pointsLabel.Text = Loc.GetString("blockgame-menu-label-points", ("points", points)); } public void UpdateLevel(int level) { _levelLabel.Text = Loc.GetString("blockgame-menu-label-level", ("level", level + 1)); } public void UpdateHighscores(List localHighscores, List globalHighscores) { var localHighscoreText = new StringBuilder(Loc.GetString("blockgame-menu-text-station") + "\n"); var globalHighscoreText = new StringBuilder(Loc.GetString("blockgame-menu-text-nanotrasen") + "\n"); for (var i = 0; i < 5; i++) { localHighscoreText.AppendLine(localHighscores.Count > i ? $"#{i + 1}: {localHighscores[i].Name} - {localHighscores[i].Score}" : $"#{i + 1}: ??? - 0"); globalHighscoreText.AppendLine(globalHighscores.Count > i ? $"#{i + 1}: {globalHighscores[i].Name} - {globalHighscores[i].Score}" : $"#{i + 1}: ??? - 0"); } _localHighscoresLabel.Text = localHighscoreText.ToString(); _globalHighscoresLabel.Text = globalHighscoreText.ToString(); } protected override void KeyBindDown(GUIBoundKeyEventArgs args) { base.KeyBindDown(args); if(!_isPlayer || args.Handled) return; if (args.Function == ContentKeyFunctions.ArcadeLeft) { _owner.SendAction(BlockGamePlayerAction.StartLeft); } else if (args.Function == ContentKeyFunctions.ArcadeRight) { _owner.SendAction(BlockGamePlayerAction.StartRight); } else if (args.Function == ContentKeyFunctions.ArcadeUp) { _owner.SendAction(BlockGamePlayerAction.Rotate); } else if (args.Function == ContentKeyFunctions.Arcade3) { _owner.SendAction(BlockGamePlayerAction.CounterRotate); } else if (args.Function == ContentKeyFunctions.ArcadeDown) { _owner.SendAction(BlockGamePlayerAction.SoftdropStart); } else if (args.Function == ContentKeyFunctions.Arcade2) { _owner.SendAction(BlockGamePlayerAction.Hold); } else if (args.Function == ContentKeyFunctions.Arcade1) { _owner.SendAction(BlockGamePlayerAction.Harddrop); } } protected override void KeyBindUp(GUIBoundKeyEventArgs args) { base.KeyBindUp(args); if(!_isPlayer || args.Handled) return; if (args.Function == ContentKeyFunctions.ArcadeLeft) { _owner.SendAction(BlockGamePlayerAction.EndLeft); } else if (args.Function == ContentKeyFunctions.ArcadeRight) { _owner.SendAction(BlockGamePlayerAction.EndRight); }else if (args.Function == ContentKeyFunctions.ArcadeDown) { _owner.SendAction(BlockGamePlayerAction.SoftdropEnd); } } public void UpdateNextBlock(BlockGameBlock[] blocks) { _nextBlockGrid.RemoveAllChildren(); if (blocks.Length == 0) return; var columnCount = blocks.Max(b => b.Position.X) + 1; var rowCount = blocks.Max(b => b.Position.Y) + 1; _nextBlockGrid.Columns = columnCount; for (int y = 0; y < rowCount; y++) { for (int x = 0; x < columnCount; x++) { var c = GetColorForPosition(blocks, x, y); _nextBlockGrid.AddChild(new PanelContainer { PanelOverride = new StyleBoxFlat {BackgroundColor = c}, MinSize = BlockSize, RectDrawClipMargin = 0 }); } } } public void UpdateHeldBlock(BlockGameBlock[] blocks) { _holdBlockGrid.RemoveAllChildren(); if (blocks.Length == 0) return; var columnCount = blocks.Max(b => b.Position.X) + 1; var rowCount = blocks.Max(b => b.Position.Y) + 1; _holdBlockGrid.Columns = columnCount; for (int y = 0; y < rowCount; y++) { for (int x = 0; x < columnCount; x++) { var c = GetColorForPosition(blocks, x, y); _holdBlockGrid.AddChild(new PanelContainer { PanelOverride = new StyleBoxFlat {BackgroundColor = c}, MinSize = BlockSize, RectDrawClipMargin = 0 }); } } } public void UpdateBlocks(BlockGameBlock[] blocks) { _gameGrid.RemoveAllChildren(); for (int y = 0; y < 20; y++) { for (int x = 0; x < 10; x++) { var c = GetColorForPosition(blocks, x, y); _gameGrid.AddChild(new PanelContainer { PanelOverride = new StyleBoxFlat {BackgroundColor = c}, MinSize = BlockSize, RectDrawClipMargin = 0 }); } } } private Color GetColorForPosition(BlockGameBlock[] blocks, int x, int y) { Color c = Color.Transparent; var matchingBlock = blocks.FirstOrNull(b => b.Position.X == x && b.Position.Y == y); if (matchingBlock.HasValue) { c = BlockGameBlock.ToColor(matchingBlock.Value.GameBlockColor); } return c; } } }