diff --git a/.envrc b/.envrc index 3550a30f2de389..5def8fd66a2752 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,4 @@ +if ! has nix_direnv_version || ! nix_direnv_version 2.3.0; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.3.0/direnvrc" "sha256-Dmd+j63L84wuzgyjITIfSxSD57Tx7v51DMxVZOsiUD8=" +fi use flake diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 627126c918b1c7..ff52456cf32b69 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,15 +1,19 @@ # Last match in file takes precedence. +# Sorting by path instead of by who added it one day :( +/Resources/ConfigPresets/WizardsDen/ @Chief-Engineer + # Moony's Gargantuan List Of Things She Cares About, or MGLOTSCA for short. # You need to add your name to these entries, not make a new one, if you care about them. /Content.*/Bql/ @moonheart08 -/Content.*/Administration/ @moonheart08 @PaulRitter @DrSmugleaf +/Content.*/Administration/ @moonheart08 @PaulRitter @DrSmugleaf @Chief-Engineer /Content.*/Station/ @moonheart08 /Content.*/Maps/ @moonheart08 /Content.*/GameTicking/ @moonheart08 -/Resources/Server\ Info/ @moonheart08 -/Resources/engineCommandPerms.yml @moonheart08 -/Resources/clientCommandPerms.yml @moonheart08 +/Resources/ServerInfo/ @moonheart08 @Chief-Engineer +/Resources/ServerInfo/Guidebook/ @moonheart08 +/Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer +/Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer /Resources/Prototypes/species.yml @moonheart08 /Resources/Prototypes/Body/ @moonheart08 @mirrorcult @DrSmugleaf # suffering /Resources/Prototypes/Maps/ @moonheart08 @Emisse @@ -50,5 +54,6 @@ # SKREEEE /Content.*.Database/ @PJB3005 @DrSmugleaf +/Content.Shared.Database/Log*.cs @PJB3005 @DrSmugleaf @Chief-Engineer /Pow3r/ @PJB3005 /Content.Server/Power/Pow3r/ @PJB3005 diff --git a/.run/Content Server+Client.run.xml b/.run/Content Server+Client.run.xml index 4ba50d81900b04..0ec9bf16a750ae 100644 --- a/.run/Content Server+Client.run.xml +++ b/.run/Content Server+Client.run.xml @@ -4,4 +4,4 @@ - \ No newline at end of file + diff --git a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs index b9880eb8b6e912..6b6ce1e5657f2f 100644 --- a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs +++ b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs @@ -25,8 +25,8 @@ protected override void Open() _window.OpenCentered(); _window.OnClose += Close; - _window.OnNameEntered += OnNameChanged; - _window.OnJobEntered += OnJobChanged; + _window.OnNameChanged += OnNameChanged; + _window.OnJobChanged += OnJobChanged; } private void OnNameChanged(string newName) diff --git a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs index 9813a2946ecfcc..1be816f0276cac 100644 --- a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs +++ b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs @@ -7,16 +7,18 @@ namespace Content.Client.Access.UI [GenerateTypedNameReferences] public sealed partial class AgentIDCardWindow : DefaultWindow { - public event Action? OnNameEntered; - - public event Action? OnJobEntered; + public event Action? OnNameChanged; + public event Action? OnJobChanged; public AgentIDCardWindow() { RobustXamlLoader.Load(this); - NameLineEdit.OnTextEntered += e => OnNameEntered?.Invoke(e.Text); - JobLineEdit.OnTextEntered += e => OnJobEntered?.Invoke(e.Text); + NameLineEdit.OnTextEntered += e => OnNameChanged?.Invoke(e.Text); + NameLineEdit.OnFocusExit += e => OnNameChanged?.Invoke(e.Text); + + JobLineEdit.OnTextEntered += e => OnJobChanged?.Invoke(e.Text); + JobLineEdit.OnFocusExit += e => OnJobChanged?.Invoke(e.Text); } public void SetCurrentName(string name) diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 08cdb8c832f7d3..3eac41d8356f75 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -173,7 +173,7 @@ public void UnlinkAllActions() public void LinkAllActions(ActionsComponent? actions = null) { var player = _playerManager.LocalPlayer?.ControlledEntity; - if (player == null || !Resolve(player.Value, ref actions)) + if (player == null || !Resolve(player.Value, ref actions, false)) { return; } diff --git a/Content.Client/Arcade/BlockGameMenu.cs b/Content.Client/Arcade/BlockGameMenu.cs index 5452d7c5d00392..17f150c756a379 100644 --- a/Content.Client/Arcade/BlockGameMenu.cs +++ b/Content.Client/Arcade/BlockGameMenu.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -20,16 +21,16 @@ namespace Content.Client.Arcade { public sealed class BlockGameMenu : DefaultWindow { - private static readonly Color OverlayBackgroundColor = new(74,74,81,180); - private static readonly Color OverlayShadowColor = new(0,0,0,83); + 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 static readonly Vector2 BlockSize = new(15, 15); private readonly BlockGameBoundUserInterface _owner; private readonly PanelContainer _mainPanel; - private BoxContainer _gameRootContainer; + private readonly BoxContainer _gameRootContainer; private GridContainer _gameGrid = default!; private GridContainer _nextBlockGrid = default!; private GridContainer _holdBlockGrid = default!; @@ -82,7 +83,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) _gameRootContainer.AddChild(_levelLabel); _gameRootContainer.AddChild(new Control { - MinSize = new Vector2(1,5) + MinSize = new Vector2(1, 5) }); _pointsLabel = new Label @@ -93,7 +94,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) _gameRootContainer.AddChild(_pointsLabel); _gameRootContainer.AddChild(new Control { - MinSize = new Vector2(1,10) + MinSize = new Vector2(1, 10) }); var gameBox = new BoxContainer @@ -103,12 +104,12 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) gameBox.AddChild(SetupHoldBox(backgroundTexture)); gameBox.AddChild(new Control { - MinSize = new Vector2(10,1) + MinSize = new Vector2(10, 1) }); gameBox.AddChild(SetupGameGrid(backgroundTexture)); gameBox.AddChild(new Control { - MinSize = new Vector2(10,1) + MinSize = new Vector2(10, 1) }); gameBox.AddChild(SetupNextBox(backgroundTexture)); @@ -116,7 +117,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) _gameRootContainer.AddChild(new Control { - MinSize = new Vector2(1,10) + MinSize = new Vector2(1, 10) }); _pauseButton = new Button @@ -176,7 +177,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) _owner.SendAction(BlockGamePlayerAction.NewGame); }; pauseMenuContainer.AddChild(_newGameButton); - pauseMenuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); + pauseMenuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); _scoreBoardButton = new Button { @@ -185,7 +186,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _scoreBoardButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.ShowHighscores); pauseMenuContainer.AddChild(_scoreBoardButton); - _unpauseButtonMargin = new Control {MinSize = new Vector2(1, 10), Visible = false}; + _unpauseButtonMargin = new Control { MinSize = new Vector2(1, 10), Visible = false }; pauseMenuContainer.AddChild(_unpauseButtonMargin); _unpauseButton = new Button @@ -239,13 +240,13 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) 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)}); + 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}; + _finalScoreLabel = new Label { Align = Label.AlignMode.Center }; gameOverMenuContainer.AddChild(_finalScoreLabel); - gameOverMenuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); + gameOverMenuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); _finalNewGameButton = new Button { @@ -275,7 +276,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) HorizontalAlignment = HAlignment.Center }; - var c = new Color(OverlayBackgroundColor.R,OverlayBackgroundColor.G,OverlayBackgroundColor.B,220); + var c = new Color(OverlayBackgroundColor.R, OverlayBackgroundColor.G, OverlayBackgroundColor.B, 220); var innerBack = new StyleBoxTexture { Texture = backgroundTexture, @@ -298,8 +299,8 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) VerticalAlignment = VAlignment.Center }; - menuContainer.AddChild(new Label{Text = Loc.GetString("blockgame-menu-label-highscores")}); - menuContainer.AddChild(new Control{MinSize = new Vector2(1,10)}); + menuContainer.AddChild(new Label { Text = Loc.GetString("blockgame-menu-label-highscores") }); + menuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); var highScoreBox = new BoxContainer { @@ -311,14 +312,14 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) Align = Label.AlignMode.Center }; highScoreBox.AddChild(_localHighscoresLabel); - highScoreBox.AddChild(new Control{MinSize = new Vector2(40,1)}); + 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)}); + menuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); _highscoreBackButton = new Button { Text = Loc.GetString("blockgame-menu-button-back"), @@ -359,7 +360,7 @@ private Control SetupGameGrid(Texture panelTex) HSeparationOverride = 1, VSeparationOverride = 1 }; - UpdateBlocks(new BlockGameBlock[0]); + UpdateBlocks(Array.Empty()); var back = new StyleBoxTexture { @@ -376,7 +377,7 @@ private Control SetupGameGrid(Texture panelTex) }; var backgroundPanel = new PanelContainer { - PanelOverride = new StyleBoxFlat{BackgroundColor = Color.FromHex("#86868d")} + PanelOverride = new StyleBoxFlat { BackgroundColor = Color.FromHex("#86868d") } }; backgroundPanel.AddChild(_gameGrid); gamePanel.AddChild(backgroundPanel); @@ -416,7 +417,7 @@ private Control SetupNextBox(Texture panelTex) nextBlockPanel.AddChild(nextCenterContainer); grid.AddChild(nextBlockPanel); - grid.AddChild(new Label{Text = Loc.GetString("blockgame-menu-label-next"), Align = Label.AlignMode.Center}); + grid.AddChild(new Label { Text = Loc.GetString("blockgame-menu-label-next"), Align = Label.AlignMode.Center }); return grid; } @@ -454,15 +455,17 @@ private Control SetupHoldBox(Texture panelTex) holdBlockPanel.AddChild(holdCenterContainer); grid.AddChild(holdBlockPanel); - grid.AddChild(new Label{Text = Loc.GetString("blockgame-menu-label-hold"), Align = Label.AlignMode.Center}); + 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; + if (!IsOpen) + return; + if (_gameOver) + return; TryPause(); } @@ -480,7 +483,8 @@ public void SetStarted() public void SetScreen(BlockGameMessages.BlockGameScreen screen) { - if (_gameOver) return; + if (_gameOver) + return; switch (screen) { @@ -512,9 +516,12 @@ public void SetScreen(BlockGameMessages.BlockGameScreen screen) 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); + 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) @@ -563,72 +570,56 @@ protected override void KeyBindDown(GUIBoundKeyEventArgs args) { base.KeyBindDown(args); - if(!_isPlayer || args.Handled) return; + if (!_isPlayer || args.Handled) + return; - if (args.Function == ContentKeyFunctions.ArcadeLeft) - { + else 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 (!_isPlayer || args.Handled) + return; - if (args.Function == ContentKeyFunctions.ArcadeLeft) - { + else 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) - { + else if (args.Function == ContentKeyFunctions.ArcadeDown) _owner.SendAction(BlockGamePlayerAction.SoftdropEnd); - } } public void UpdateNextBlock(BlockGameBlock[] blocks) { _nextBlockGrid.RemoveAllChildren(); - if (blocks.Length == 0) return; + 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 (var y = 0; y < rowCount; y++) { - for (int x = 0; x < columnCount; x++) + for (var x = 0; x < columnCount; x++) { var c = GetColorForPosition(blocks, x, y); _nextBlockGrid.AddChild(new PanelContainer { - PanelOverride = new StyleBoxFlat {BackgroundColor = c}, + PanelOverride = new StyleBoxFlat { BackgroundColor = c }, MinSize = BlockSize, RectDrawClipMargin = 0 }); @@ -639,18 +630,19 @@ public void UpdateNextBlock(BlockGameBlock[] blocks) public void UpdateHeldBlock(BlockGameBlock[] blocks) { _holdBlockGrid.RemoveAllChildren(); - if (blocks.Length == 0) return; + 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 (var y = 0; y < rowCount; y++) { - for (int x = 0; x < columnCount; x++) + for (var x = 0; x < columnCount; x++) { var c = GetColorForPosition(blocks, x, y); _holdBlockGrid.AddChild(new PanelContainer { - PanelOverride = new StyleBoxFlat {BackgroundColor = c}, + PanelOverride = new StyleBoxFlat { BackgroundColor = c }, MinSize = BlockSize, RectDrawClipMargin = 0 }); @@ -661,14 +653,14 @@ public void UpdateHeldBlock(BlockGameBlock[] blocks) public void UpdateBlocks(BlockGameBlock[] blocks) { _gameGrid.RemoveAllChildren(); - for (int y = 0; y < 20; y++) + for (var y = 0; y < 20; y++) { - for (int x = 0; x < 10; x++) + for (var x = 0; x < 10; x++) { var c = GetColorForPosition(blocks, x, y); _gameGrid.AddChild(new PanelContainer { - PanelOverride = new StyleBoxFlat {BackgroundColor = c}, + PanelOverride = new StyleBoxFlat { BackgroundColor = c }, MinSize = BlockSize, RectDrawClipMargin = 0 }); @@ -676,9 +668,9 @@ public void UpdateBlocks(BlockGameBlock[] blocks) } } - private Color GetColorForPosition(BlockGameBlock[] blocks, int x, int y) + private static Color GetColorForPosition(BlockGameBlock[] blocks, int x, int y) { - Color c = Color.Transparent; + var c = Color.Transparent; var matchingBlock = blocks.FirstOrNull(b => b.Position.X == x && b.Position.Y == y); if (matchingBlock.HasValue) { diff --git a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs index bbd763545905f7..4f07593b0e1caa 100644 --- a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs +++ b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs @@ -24,40 +24,46 @@ public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) Title = Loc.GetString("spacevillain-menu-title"); Owner = owner; - var grid = new GridContainer {Columns = 1}; + var grid = new GridContainer { Columns = 1 }; - var infoGrid = new GridContainer {Columns = 3}; - infoGrid.AddChild(new Label{ Text = Loc.GetString("spacevillain-menu-label-player"), Align = Label.AlignMode.Center }); - infoGrid.AddChild(new Label{ Text = "|", Align = Label.AlignMode.Center }); - _enemyNameLabel = new Label{ Align = Label.AlignMode.Center}; + var infoGrid = new GridContainer { Columns = 3 }; + infoGrid.AddChild(new Label { Text = Loc.GetString("spacevillain-menu-label-player"), Align = Label.AlignMode.Center }); + infoGrid.AddChild(new Label { Text = "|", Align = Label.AlignMode.Center }); + _enemyNameLabel = new Label { Align = Label.AlignMode.Center }; infoGrid.AddChild(_enemyNameLabel); - _playerInfoLabel = new Label {Align = Label.AlignMode.Center}; + _playerInfoLabel = new Label { Align = Label.AlignMode.Center }; infoGrid.AddChild(_playerInfoLabel); - infoGrid.AddChild(new Label{ Text = "|", Align = Label.AlignMode.Center }); - _enemyInfoLabel = new Label {Align = Label.AlignMode.Center}; + infoGrid.AddChild(new Label { Text = "|", Align = Label.AlignMode.Center }); + _enemyInfoLabel = new Label { Align = Label.AlignMode.Center }; infoGrid.AddChild(_enemyInfoLabel); var centerContainer = new CenterContainer(); centerContainer.AddChild(infoGrid); grid.AddChild(centerContainer); - _playerActionLabel = new Label {Align = Label.AlignMode.Center}; + _playerActionLabel = new Label { Align = Label.AlignMode.Center }; grid.AddChild(_playerActionLabel); - _enemyActionLabel = new Label {Align = Label.AlignMode.Center}; + _enemyActionLabel = new Label { Align = Label.AlignMode.Center }; grid.AddChild(_enemyActionLabel); - var buttonGrid = new GridContainer {Columns = 3}; + var buttonGrid = new GridContainer { Columns = 3 }; _gameButtons[0] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Attack) - {Text = Loc.GetString("spacevillain-menu-button-attack")}; + { + Text = Loc.GetString("spacevillain-menu-button-attack") + }; buttonGrid.AddChild(_gameButtons[0]); _gameButtons[1] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Heal) - {Text = Loc.GetString("spacevillain-menu-button-heal")}; + { + Text = Loc.GetString("spacevillain-menu-button-heal") + }; buttonGrid.AddChild(_gameButtons[1]); _gameButtons[2] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Recharge) - {Text = Loc.GetString("spacevillain-menu-button-recharge")}; + { + Text = Loc.GetString("spacevillain-menu-button-recharge") + }; buttonGrid.AddChild(_gameButtons[2]); centerContainer = new CenterContainer(); @@ -65,7 +71,9 @@ public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) grid.AddChild(centerContainer); var newGame = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.NewGame) - {Text = Loc.GetString("spacevillain-menu-button-new-game")}; + { + Text = Loc.GetString("spacevillain-menu-button-new-game") + }; grid.AddChild(newGame); Contents.AddChild(grid); @@ -84,7 +92,8 @@ private void UpdateMetadata(SharedSpaceVillainArcadeComponent.SpaceVillainArcade public void UpdateInfo(SharedSpaceVillainArcadeComponent.SpaceVillainArcadeDataUpdateMessage message) { - if(message is SharedSpaceVillainArcadeComponent.SpaceVillainArcadeMetaDataUpdateMessage metaMessage) UpdateMetadata(metaMessage); + if (message is SharedSpaceVillainArcadeComponent.SpaceVillainArcadeMetaDataUpdateMessage metaMessage) + UpdateMetadata(metaMessage); _playerInfoLabel.Text = $"HP: {message.PlayerHP} MP: {message.PlayerMP}"; _enemyInfoLabel.Text = $"HP: {message.EnemyHP} MP: {message.EnemyMP}"; @@ -97,7 +106,7 @@ private sealed class ActionButton : Button private readonly SpaceVillainArcadeBoundUserInterface _owner; private readonly SharedSpaceVillainArcadeComponent.PlayerAction _playerAction; - public ActionButton(SpaceVillainArcadeBoundUserInterface owner,SharedSpaceVillainArcadeComponent.PlayerAction playerAction) + public ActionButton(SpaceVillainArcadeBoundUserInterface owner, SharedSpaceVillainArcadeComponent.PlayerAction playerAction) { _owner = owner; _playerAction = playerAction; diff --git a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs index cd74077c12fc5a..2abe9311fb5f87 100644 --- a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs @@ -1,78 +1,76 @@ using Content.Shared.Arcade; using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -namespace Content.Client.Arcade.UI +namespace Content.Client.Arcade.UI; + +public sealed class BlockGameBoundUserInterface : BoundUserInterface { - public sealed class BlockGameBoundUserInterface : BoundUserInterface - { - private BlockGameMenu? _menu; + private BlockGameMenu? _menu; - public BlockGameBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) - { - } + public BlockGameBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) + { + } - protected override void Open() - { - base.Open(); + protected override void Open() + { + base.Open(); - _menu = new BlockGameMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); - } + _menu = new BlockGameMenu(this); + _menu.OnClose += Close; + _menu.OpenCentered(); + } - protected override void ReceiveMessage(BoundUserInterfaceMessage message) + protected override void ReceiveMessage(BoundUserInterfaceMessage message) + { + switch (message) { - switch (message) - { - case BlockGameMessages.BlockGameVisualUpdateMessage updateMessage: - switch (updateMessage.GameVisualType) - { - case BlockGameMessages.BlockGameVisualType.GameField: - _menu?.UpdateBlocks(updateMessage.Blocks); - break; - case BlockGameMessages.BlockGameVisualType.HoldBlock: - _menu?.UpdateHeldBlock(updateMessage.Blocks); - break; - case BlockGameMessages.BlockGameVisualType.NextBlock: - _menu?.UpdateNextBlock(updateMessage.Blocks); - break; - } - break; - case BlockGameMessages.BlockGameScoreUpdateMessage scoreUpdate: - _menu?.UpdatePoints(scoreUpdate.Points); - break; - case BlockGameMessages.BlockGameUserStatusMessage userMessage: - _menu?.SetUsability(userMessage.IsPlayer); - break; - case BlockGameMessages.BlockGameSetScreenMessage statusMessage: - if (statusMessage.IsStarted) _menu?.SetStarted(); - _menu?.SetScreen(statusMessage.Screen); - if (statusMessage is BlockGameMessages.BlockGameGameOverScreenMessage gameOverScreenMessage) - _menu?.SetGameoverInfo(gameOverScreenMessage.FinalScore, gameOverScreenMessage.LocalPlacement, gameOverScreenMessage.GlobalPlacement); - break; - case BlockGameMessages.BlockGameHighScoreUpdateMessage highScoreUpdateMessage: - _menu?.UpdateHighscores(highScoreUpdateMessage.LocalHighscores, - highScoreUpdateMessage.GlobalHighscores); - break; - case BlockGameMessages.BlockGameLevelUpdateMessage levelUpdateMessage: - _menu?.UpdateLevel(levelUpdateMessage.Level); - break; - } + case BlockGameMessages.BlockGameVisualUpdateMessage updateMessage: + switch (updateMessage.GameVisualType) + { + case BlockGameMessages.BlockGameVisualType.GameField: + _menu?.UpdateBlocks(updateMessage.Blocks); + break; + case BlockGameMessages.BlockGameVisualType.HoldBlock: + _menu?.UpdateHeldBlock(updateMessage.Blocks); + break; + case BlockGameMessages.BlockGameVisualType.NextBlock: + _menu?.UpdateNextBlock(updateMessage.Blocks); + break; + } + break; + case BlockGameMessages.BlockGameScoreUpdateMessage scoreUpdate: + _menu?.UpdatePoints(scoreUpdate.Points); + break; + case BlockGameMessages.BlockGameUserStatusMessage userMessage: + _menu?.SetUsability(userMessage.IsPlayer); + break; + case BlockGameMessages.BlockGameSetScreenMessage statusMessage: + if (statusMessage.IsStarted) _menu?.SetStarted(); + _menu?.SetScreen(statusMessage.Screen); + if (statusMessage is BlockGameMessages.BlockGameGameOverScreenMessage gameOverScreenMessage) + _menu?.SetGameoverInfo(gameOverScreenMessage.FinalScore, gameOverScreenMessage.LocalPlacement, gameOverScreenMessage.GlobalPlacement); + break; + case BlockGameMessages.BlockGameHighScoreUpdateMessage highScoreUpdateMessage: + _menu?.UpdateHighscores(highScoreUpdateMessage.LocalHighscores, + highScoreUpdateMessage.GlobalHighscores); + break; + case BlockGameMessages.BlockGameLevelUpdateMessage levelUpdateMessage: + _menu?.UpdateLevel(levelUpdateMessage.Level); + break; } + } - public void SendAction(BlockGamePlayerAction action) - { - SendMessage(new BlockGameMessages.BlockGamePlayerActionMessage(action)); - } + public void SendAction(BlockGamePlayerAction action) + { + SendMessage(new BlockGameMessages.BlockGamePlayerActionMessage(action)); + } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; - _menu?.Dispose(); - } + _menu?.Dispose(); } } diff --git a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs index bb1582d12793af..2ecc8b46a85a15 100644 --- a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs @@ -3,51 +3,45 @@ using Robust.Shared.ViewVariables; using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent; -namespace Content.Client.Arcade.UI -{ - public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface - { - [ViewVariables] private SpaceVillainArcadeMenu? _menu; +namespace Content.Client.Arcade.UI; - //public SharedSpaceVillainArcadeComponent SpaceVillainArcade; - - public SpaceVillainArcadeBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) - { - SendAction(PlayerAction.RequestData); - } +public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface +{ + [ViewVariables] private SpaceVillainArcadeMenu? _menu; - public void SendAction(PlayerAction action) - { - SendMessage(new SpaceVillainArcadePlayerActionMessage(action)); - } + //public SharedSpaceVillainArcadeComponent SpaceVillainArcade; - protected override void Open() - { - base.Open(); + public SpaceVillainArcadeBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) + { + SendAction(PlayerAction.RequestData); + } - /*if(!Owner.Owner.TryGetComponent(out SharedSpaceVillainArcadeComponent spaceVillainArcade)) - { - return; - } + public void SendAction(PlayerAction action) + { + SendMessage(new SpaceVillainArcadePlayerActionMessage(action)); + } - SpaceVillainArcade = spaceVillainArcade;*/ + protected override void Open() + { + base.Open(); - _menu = new SpaceVillainArcadeMenu(this); + _menu = new SpaceVillainArcadeMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); - } + _menu.OnClose += Close; + _menu.OpenCentered(); + } - protected override void ReceiveMessage(BoundUserInterfaceMessage message) - { - if (message is SpaceVillainArcadeDataUpdateMessage msg) _menu?.UpdateInfo(msg); - } + protected override void ReceiveMessage(BoundUserInterfaceMessage message) + { + if (message is SpaceVillainArcadeDataUpdateMessage msg) + _menu?.UpdateInfo(msg); + } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); - if (disposing) _menu?.Dispose(); - } + if (disposing) + _menu?.Dispose(); } } diff --git a/Content.Client/Audio/AmbientSoundSystem.cs b/Content.Client/Audio/AmbientSoundSystem.cs index e357e63c25469e..d241df4f6fc341 100644 --- a/Content.Client/Audio/AmbientSoundSystem.cs +++ b/Content.Client/Audio/AmbientSoundSystem.cs @@ -11,6 +11,7 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using System.Linq; +using Robust.Client.GameObjects; namespace Content.Client.Audio { @@ -106,7 +107,19 @@ private void OnShutdown(EntityUid uid, AmbientSoundComponent component, Componen _playingCount.Remove(sound.Sound); } - private void SetAmbienceVolume(float value) => _ambienceVolume = value; + private void SetAmbienceVolume(float value) + { + _ambienceVolume = value; + + foreach (var (comp, values) in _playingSounds) + { + if (values.Stream == null) + continue; + + var stream = (AudioSystem.PlayingStream) values.Stream; + stream.Volume = _params.Volume + comp.Volume + _ambienceVolume; + } + } private void SetCooldown(float value) => _cooldown = value; private void SetAmbientCount(int value) => _maxAmbientCount = value; private void SetAmbientRange(float value) => _maxAmbientRange = value; diff --git a/Content.Client/Audio/BackgroundAudioSystem.cs b/Content.Client/Audio/BackgroundAudioSystem.cs index 50639a6d05eae3..100ee7458e61a3 100644 --- a/Content.Client/Audio/BackgroundAudioSystem.cs +++ b/Content.Client/Audio/BackgroundAudioSystem.cs @@ -1,21 +1,12 @@ -using System.Threading; -using Content.Client.Gameplay; using Content.Client.GameTicking.Managers; using Content.Client.Lobby; using Content.Shared.CCVar; using JetBrains.Annotations; using Robust.Client; -using Robust.Client.GameObjects; -using Robust.Client.Player; -using Robust.Client.ResourceManagement; using Robust.Client.State; using Robust.Shared.Audio; using Robust.Shared.Configuration; using Robust.Shared.Player; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Timing; -using Timer = Robust.Shared.Timing.Timer; namespace Content.Client.Audio; @@ -26,57 +17,18 @@ public sealed class BackgroundAudioSystem : EntitySystem [Dependency] private readonly IBaseClient _client = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly ClientGameTicker _gameTicker = default!; - [Dependency] private readonly IPlayerManager _playMan = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _robustRandom = default!; [Dependency] private readonly IStateManager _stateManager = default!; - [Dependency] private readonly IGameTiming _timing = default!; - private readonly AudioParams _ambientParams = new(-10f, 1, "Master", 0, 0, 0, true, 0f); private readonly AudioParams _lobbyParams = new(-5f, 1, "Master", 0, 0, 0, true, 0f); - private IPlayingAudioStream? _ambientStream; private IPlayingAudioStream? _lobbyStream; - /// - /// What is currently playing. - /// - private SoundCollectionPrototype? _playingCollection; - - /// - /// What the ambience has been set to. - /// - private SoundCollectionPrototype? _currentCollection; - private CancellationTokenSource _timerCancelTokenSource = new(); - - private SoundCollectionPrototype _spaceAmbience = default!; - private SoundCollectionPrototype _stationAmbience = default!; - public override void Initialize() { base.Initialize(); - _stationAmbience = _prototypeManager.Index("StationAmbienceBase"); - _spaceAmbience = _prototypeManager.Index("SpaceAmbienceBase"); - _currentCollection = _stationAmbience; - - // TODO: Ideally audio loading streamed better / we have more robust audio but this is quite annoying - var cache = IoCManager.Resolve(); - - foreach (var audio in _spaceAmbience.PickFiles) - { - cache.GetResource(audio.ToString()); - } - - _configManager.OnValueChanged(CCVars.AmbienceVolume, AmbienceCVarChanged); _configManager.OnValueChanged(CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged); _configManager.OnValueChanged(CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged); - _configManager.OnValueChanged(CCVars.StationAmbienceEnabled, StationAmbienceCVarChanged); - _configManager.OnValueChanged(CCVars.SpaceAmbienceEnabled, SpaceAmbienceCVarChanged); - - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(EntParentChanged); - SubscribeLocalEvent(OnPlayerDetached); _stateManager.OnStateChanged += StateManagerOnStateChanged; @@ -85,28 +37,12 @@ public override void Initialize() _gameTicker.LobbyStatusUpdated += LobbySongReceived; } - private void OnPlayerAttached(PlayerAttachedEvent ev) - { - if (!TryComp(ev.Entity, out var xform)) - return; - - CheckAmbience(xform); - } - - private void OnPlayerDetached(PlayerDetachedEvent ev) - { - EndAmbience(); - } - public override void Shutdown() { base.Shutdown(); - _configManager.UnsubValueChanged(CCVars.AmbienceVolume, AmbienceCVarChanged); _configManager.UnsubValueChanged(CCVars.LobbyMusicEnabled, LobbyMusicCVarChanged); _configManager.UnsubValueChanged(CCVars.LobbyMusicVolume, LobbyMusicVolumeCVarChanged); - _configManager.UnsubValueChanged(CCVars.StationAmbienceEnabled, StationAmbienceCVarChanged); - _configManager.UnsubValueChanged(CCVars.SpaceAmbienceEnabled, SpaceAmbienceCVarChanged); _stateManager.OnStateChanged -= StateManagerOnStateChanged; @@ -114,61 +50,17 @@ public override void Shutdown() _gameTicker.LobbyStatusUpdated -= LobbySongReceived; - EndAmbience(); EndLobbyMusic(); } - private void CheckAmbience(TransformComponent xform) - { - if (xform.GridUid != null) - ChangeAmbience(_stationAmbience); - else - ChangeAmbience(_spaceAmbience); - } - - private void EntParentChanged(ref EntParentChangedMessage message) - { - if (_playMan.LocalPlayer is null - || _playMan.LocalPlayer.ControlledEntity != message.Entity - || !(_timing.IsFirstTimePredicted || _timing.ApplyingState)) - return; - - // Check if we traversed to grid. - CheckAmbience(message.Transform); - } - - private void ChangeAmbience(SoundCollectionPrototype newAmbience) - { - if (_currentCollection == newAmbience) - return; - - _timerCancelTokenSource.Cancel(); - _currentCollection = newAmbience; - _timerCancelTokenSource = new CancellationTokenSource(); - Timer.Spawn(1500, () => - { - // If we traverse a few times then don't interrupt an existing song. - // If we are not in gameplay, don't call StartAmbience because of player movement - if (_playingCollection == _currentCollection || _stateManager.CurrentState is not GameplayState) - return; - StartAmbience(); - }, _timerCancelTokenSource.Token); - } - private void StateManagerOnStateChanged(StateChangedEventArgs args) { switch (args.NewState) { case LobbyState: - EndAmbience(); StartLobbyMusic(); break; - case GameplayState: - EndLobbyMusic(); - StartAmbience(); - break; default: - EndAmbience(); EndLobbyMusic(); break; } @@ -176,80 +68,9 @@ private void StateManagerOnStateChanged(StateChangedEventArgs args) private void OnLeave(object? sender, PlayerEventArgs args) { - EndAmbience(); EndLobbyMusic(); } - private void AmbienceCVarChanged(float volume) - { - if (_stateManager.CurrentState is GameplayState) - { - StartAmbience(); - } - else - { - EndAmbience(); - } - } - - private void StartAmbience() - { - EndAmbience(); - if (_currentCollection == null || !CanPlayCollection(_currentCollection)) - return; - _playingCollection = _currentCollection; - var file = _robustRandom.Pick(_currentCollection.PickFiles).ToString(); - _ambientStream = _audio.PlayGlobal(file, Filter.Local(), false, - _ambientParams.WithVolume(_ambientParams.Volume + _configManager.GetCVar(CCVars.AmbienceVolume))); - } - - private void EndAmbience() - { - _playingCollection = null; - _ambientStream?.Stop(); - _ambientStream = null; - } - - private bool CanPlayCollection(SoundCollectionPrototype collection) - { - if (collection.ID == _spaceAmbience.ID) - return _configManager.GetCVar(CCVars.SpaceAmbienceEnabled); - if (collection.ID == _stationAmbience.ID) - return _configManager.GetCVar(CCVars.StationAmbienceEnabled); - - return true; - } - - private void StationAmbienceCVarChanged(bool enabled) - { - if (_currentCollection == null) - return; - - if (enabled && _stateManager.CurrentState is GameplayState && _currentCollection.ID == _stationAmbience.ID) - { - StartAmbience(); - } - else if (_currentCollection.ID == _stationAmbience.ID) - { - EndAmbience(); - } - } - - private void SpaceAmbienceCVarChanged(bool enabled) - { - if (_currentCollection == null) - return; - - if (enabled && _stateManager.CurrentState is GameplayState && _currentCollection.ID == _spaceAmbience.ID) - { - StartAmbience(); - } - else if (_currentCollection.ID == _spaceAmbience.ID) - { - EndAmbience(); - } - } - private void LobbyMusicVolumeCVarChanged(float volume) { if (_stateManager.CurrentState is LobbyState) diff --git a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs new file mode 100644 index 00000000000000..34bc83bdfb467e --- /dev/null +++ b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs @@ -0,0 +1,262 @@ +using System.Linq; +using Content.Client.Gameplay; +using Content.Shared.Audio; +using Content.Shared.CCVar; +using Content.Shared.GameTicking; +using Content.Shared.Random; +using Robust.Client.GameObjects; +using Robust.Client.Player; +using Robust.Client.ResourceManagement; +using Robust.Client.State; +using Robust.Shared.Audio; +using Robust.Shared.Configuration; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Timing; +using Robust.Shared.Utility; + +namespace Content.Client.Audio; + +public sealed partial class ContentAudioSystem +{ + [Dependency] private readonly IConfigurationManager _configManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IResourceCache _resource = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IStateManager _state = default!; + [Dependency] private readonly RulesSystem _rules = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + private readonly TimeSpan _minAmbienceTime = TimeSpan.FromSeconds(30); + private readonly TimeSpan _maxAmbienceTime = TimeSpan.FromSeconds(60); + + private const float AmbientMusicFadeTime = 10f; + private static float _volumeSlider; + + // Don't need to worry about this being serializable or pauseable as it doesn't affect the sim. + private TimeSpan _nextAudio; + + private AudioSystem.PlayingStream? _ambientMusicStream; + private AmbientMusicPrototype? _musicProto; + + /// + /// If we find a better ambient music proto can we interrupt this one. + /// + private bool _interruptable; + + /// + /// Track what ambient sounds we've played. This is so they all get played an even + /// number of times. + /// When we get to the end of the list we'll re-shuffle + /// + private readonly Dictionary> _ambientSounds = new(); + + private ISawmill _sawmill = default!; + + private void InitializeAmbientMusic() + { + // TODO: Shitty preload + foreach (var audio in _proto.Index("AmbienceSpace").PickFiles) + { + _resource.GetResource(audio.ToString()); + } + + _configManager.OnValueChanged(CCVars.AmbientMusicVolume, AmbienceCVarChanged, true); + _sawmill = IoCManager.Resolve().GetSawmill("audio.ambience"); + + // Reset audio + _nextAudio = TimeSpan.MaxValue; + + SetupAmbientSounds(); + _proto.PrototypesReloaded += OnProtoReload; + _state.OnStateChanged += OnStateChange; + // On round end summary OR lobby cut audio. + SubscribeNetworkEvent(OnRoundEndMessage); + } + + private void AmbienceCVarChanged(float obj) + { + _volumeSlider = obj; + + if (_ambientMusicStream != null && _musicProto != null) + { + _ambientMusicStream.Volume = _musicProto.Sound.Params.Volume + _volumeSlider; + } + } + + private void ShutdownAmbientMusic() + { + _configManager.UnsubValueChanged(CCVars.AmbientMusicVolume, AmbienceCVarChanged); + _proto.PrototypesReloaded -= OnProtoReload; + _state.OnStateChanged -= OnStateChange; + _ambientMusicStream?.Stop(); + } + + private void OnProtoReload(PrototypesReloadedEventArgs obj) + { + if (!obj.ByType.ContainsKey(typeof(AmbientMusicPrototype)) && + !obj.ByType.ContainsKey(typeof(RulesPrototype))) + { + return; + } + + _ambientSounds.Clear(); + SetupAmbientSounds(); + } + + private void OnStateChange(StateChangedEventArgs obj) + { + if (obj.NewState is not GameplayState) + return; + + // If they go to game then reset the ambience timer. + _nextAudio = _timing.CurTime + _random.Next(_minAmbienceTime, _maxAmbienceTime); + } + + private void SetupAmbientSounds() + { + foreach (var ambience in _proto.EnumeratePrototypes()) + { + var tracks = _ambientSounds.GetOrNew(ambience.ID); + RefreshTracks(ambience.Sound, tracks, null); + _random.Shuffle(tracks); + } + } + + private void OnRoundEndMessage(RoundEndMessageEvent ev) + { + // If scoreboard shows then just stop the music + _ambientMusicStream?.Stop(); + _ambientMusicStream = null; + _nextAudio = TimeSpan.FromMinutes(3); + } + + private void RefreshTracks(SoundSpecifier sound, List tracks, ResPath? lastPlayed) + { + DebugTools.Assert(tracks.Count == 0); + + switch (sound) + { + case SoundCollectionSpecifier collection: + if (collection.Collection == null) + break; + + var slothCud = _proto.Index(collection.Collection); + tracks.AddRange(slothCud.PickFiles); + break; + case SoundPathSpecifier path: + tracks.Add(path.Path); + break; + } + + // Just so the same track doesn't play twice + if (tracks.Count > 1 && tracks[^1] == lastPlayed) + { + (tracks[0], tracks[^1]) = (tracks[^1], tracks[0]); + } + } + + private void UpdateAmbientMusic() + { + // Update still runs in lobby so just ignore it. + if (_state.CurrentState is not GameplayState) + { + FadeOut(_ambientMusicStream); + _ambientMusicStream = null; + _musicProto = null; + return; + } + + var isDone = _ambientMusicStream?.Done; + + if (_interruptable) + { + var player = _player.LocalPlayer?.ControlledEntity; + + if (player == null || _musicProto == null || !_rules.IsTrue(player.Value, _proto.Index(_musicProto.Rules))) + { + FadeOut(_ambientMusicStream, AmbientMusicFadeTime); + _musicProto = null; + _interruptable = false; + isDone = true; + } + } + + // Still running existing ambience + if (isDone == false) + return; + + // If ambience finished reset the CD (this also means if we have long ambience it won't clip) + if (isDone == true) + { + // Also don't need to worry about rounding here as it doesn't affect the sim + _nextAudio = _timing.CurTime + _random.Next(_minAmbienceTime, _maxAmbienceTime); + } + + _ambientMusicStream = null; + + if (_nextAudio > _timing.CurTime) + return; + + _musicProto = GetAmbience(); + + if (_musicProto == null) + { + _interruptable = false; + return; + } + + _interruptable = _musicProto.Interruptable; + var tracks = _ambientSounds[_musicProto.ID]; + + var track = tracks[^1]; + tracks.RemoveAt(tracks.Count - 1); + + var strim = _audio.PlayGlobal( + track.ToString(), + Filter.Local(), + false, + AudioParams.Default.WithVolume(_musicProto.Sound.Params.Volume + _volumeSlider)); + + if (strim != null) + { + _ambientMusicStream = (AudioSystem.PlayingStream) strim; + + if (_musicProto.FadeIn) + { + FadeIn(_ambientMusicStream, AmbientMusicFadeTime); + } + } + + // Refresh the list + if (tracks.Count == 0) + { + RefreshTracks(_musicProto.Sound, tracks, track); + } + } + + private AmbientMusicPrototype? GetAmbience() + { + var player = _player.LocalPlayer?.ControlledEntity; + + if (player == null) + return null; + + var ambiences = _proto.EnumeratePrototypes().ToList(); + ambiences.Sort((x, y) => y.Priority.CompareTo(x.Priority)); + + foreach (var amb in ambiences) + { + if (!_rules.IsTrue(player.Value, _proto.Index(amb.Rules))) + continue; + + return amb; + } + + _sawmill.Warning($"Unable to find fallback ambience track"); + return null; + } +} diff --git a/Content.Client/Audio/ContentAudioSystem.cs b/Content.Client/Audio/ContentAudioSystem.cs index 7d19acf6efa05a..cd6a88f01d6d28 100644 --- a/Content.Client/Audio/ContentAudioSystem.cs +++ b/Content.Client/Audio/ContentAudioSystem.cs @@ -1,8 +1,124 @@ using Content.Shared.Audio; +using Robust.Client.GameObjects; namespace Content.Client.Audio; -public sealed class ContentAudioSystem : SharedContentAudioSystem +public sealed partial class ContentAudioSystem : SharedContentAudioSystem { + // Need how much volume to change per tick and just remove it when it drops below "0" + private readonly Dictionary _fadingOut = new(); + // Need volume change per tick + target volume. + private readonly Dictionary _fadingIn = new(); + + private readonly List _fadeToRemove = new(); + + private const float MinVolume = -32f; + private const float DefaultDuration = 2f; + + public override void Initialize() + { + base.Initialize(); + UpdatesOutsidePrediction = true; + InitializeAmbientMusic(); + } + + public override void Shutdown() + { + base.Shutdown(); + ShutdownAmbientMusic(); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!_timing.IsFirstTimePredicted) + return; + + UpdateAmbientMusic(); + UpdateFades(frameTime); + } + + #region Fades + + public void FadeOut(AudioSystem.PlayingStream? stream, float duration = DefaultDuration) + { + if (stream == null || duration <= 0f) + return; + + // Just in case + // TODO: Maybe handle the removals by making it seamless? + _fadingIn.Remove(stream); + var diff = stream.Volume - MinVolume; + _fadingOut.Add(stream, diff / duration); + } + + public void FadeIn(AudioSystem.PlayingStream? stream, float duration = DefaultDuration) + { + if (stream == null || duration <= 0f || stream.Volume < MinVolume) + return; + + _fadingOut.Remove(stream); + var curVolume = stream.Volume; + var change = (curVolume - MinVolume) / duration; + _fadingIn.Add(stream, (change, stream.Volume)); + stream.Volume = MinVolume; + } + + private void UpdateFades(float frameTime) + { + _fadeToRemove.Clear(); + + foreach (var (stream, change) in _fadingOut) + { + // Cancelled elsewhere + if (stream.Done) + { + _fadeToRemove.Add(stream); + continue; + } + + var volume = stream.Volume - change * frameTime; + stream.Volume = MathF.Max(MinVolume, volume); + + if (stream.Volume.Equals(MinVolume)) + { + stream.Stop(); + _fadeToRemove.Add(stream); + } + } + + foreach (var stream in _fadeToRemove) + { + _fadingOut.Remove(stream); + } + + _fadeToRemove.Clear(); + + foreach (var (stream, (change, target)) in _fadingIn) + { + // Cancelled elsewhere + if (stream.Done) + { + _fadeToRemove.Add(stream); + continue; + } + + var volume = stream.Volume + change * frameTime; + stream.Volume = MathF.Min(target, volume); + + if (stream.Volume.Equals(target)) + { + _fadeToRemove.Add(stream); + } + } + + foreach (var stream in _fadeToRemove) + { + _fadingIn.Remove(stream); + } + } + + #endregion } diff --git a/Content.Client/Bql/BqlResultsEui.cs b/Content.Client/Bql/BqlResultsEui.cs new file mode 100644 index 00000000000000..3e9bda57ff3072 --- /dev/null +++ b/Content.Client/Bql/BqlResultsEui.cs @@ -0,0 +1,45 @@ +using Content.Client.Eui; +using Content.Shared.Bql; +using Content.Shared.Eui; +using JetBrains.Annotations; +using Robust.Client.Console; + +namespace Content.Client.Bql; + +[UsedImplicitly] +public sealed class BqlResultsEui : BaseEui +{ + private readonly BqlResultsWindow _window; + + public BqlResultsEui() + { + _window = new BqlResultsWindow( + IoCManager.Resolve(), + IoCManager.Resolve() + ); + + _window.OnClose += () => SendMessage(new CloseEuiMessage()); + } + + public override void HandleState(EuiStateBase state) + { + if (state is not BqlResultsEuiState castState) + return; + + _window.Update(castState.Entities); + } + + public override void Closed() + { + base.Closed(); + + _window.Close(); + } + + public override void Opened() + { + base.Opened(); + + _window.OpenCentered(); + } +} diff --git a/Content.Client/Bql/BqlResultsWindow.xaml b/Content.Client/Bql/BqlResultsWindow.xaml new file mode 100644 index 00000000000000..9affbf2181ac8c --- /dev/null +++ b/Content.Client/Bql/BqlResultsWindow.xaml @@ -0,0 +1,10 @@ + + + + diff --git a/Content.Client/Bql/BqlResultsWindow.xaml.cs b/Content.Client/Bql/BqlResultsWindow.xaml.cs new file mode 100644 index 00000000000000..7adceb5d773781 --- /dev/null +++ b/Content.Client/Bql/BqlResultsWindow.xaml.cs @@ -0,0 +1,48 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.Console; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Bql; + +[GenerateTypedNameReferences] +internal sealed partial class BqlResultsWindow : DefaultWindow +{ + private readonly IClientConsoleHost _console; + private readonly ILocalizationManager _loc; + + public BqlResultsWindow(IClientConsoleHost console, ILocalizationManager loc) + { + _console = console; + _loc = loc; + + RobustXamlLoader.Load(this); + } + + protected override Vector2 ContentsMinimumSize => (500, 700); + + public void Update((string name, EntityUid entity)[] entities) + { + StatusLabel.Text = _loc.GetString("ui-bql-results-status", ("count", entities.Length)); + ItemList.RemoveAllChildren(); + + foreach (var (name, entity) in entities) + { + var nameLabel = new Label { Text = name, HorizontalExpand = true }; + var tpButton = new Button { Text = _loc.GetString("ui-bql-results-tp") }; + tpButton.OnPressed += _ => _console.ExecuteCommand($"tpto {entity}"); + tpButton.ToolTip = _loc.GetString("ui-bql-results-tp-tooltip"); + + var vvButton = new Button { Text = _loc.GetString("ui-bql-results-vv") }; + vvButton.ToolTip = _loc.GetString("ui-bql-results-vv-tooltip"); + vvButton.OnPressed += _ => _console.ExecuteCommand($"vv {entity}"); + + ItemList.AddChild(new BoxContainer + { + Orientation = BoxContainer.LayoutOrientation.Horizontal, + Children = { nameLabel, tpButton, vvButton } + }); + } + } +} diff --git a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs new file mode 100644 index 00000000000000..63587d9875b409 --- /dev/null +++ b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs @@ -0,0 +1,54 @@ +using Content.Client.Cargo.UI; +using Content.Shared.Cargo.Components; +using JetBrains.Annotations; +using Robust.Client.GameObjects; + +namespace Content.Client.Cargo.BUI; + +[UsedImplicitly] +public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface +{ + [ViewVariables] + private CargoBountyMenu? _menu; + + public CargoBountyConsoleBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey) + { + + } + + protected override void Open() + { + base.Open(); + + _menu = new(); + + _menu.OnClose += Close; + + _menu.OnLabelButtonPressed += id => + { + SendMessage(new BountyPrintLabelMessage(id)); + }; + + _menu.OpenCentered(); + } + + protected override void UpdateState(BoundUserInterfaceState message) + { + base.UpdateState(message); + + if (message is not CargoBountyConsoleState state) + return; + + _menu?.UpdateEntries(state.Bounties); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) + return; + + _menu?.Dispose(); + } +} diff --git a/Content.Client/Cargo/CargoTelepadComponent.cs b/Content.Client/Cargo/CargoTelepadComponent.cs deleted file mode 100644 index 884718f78316aa..00000000000000 --- a/Content.Client/Cargo/CargoTelepadComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Content.Shared.Cargo.Components; -using Robust.Shared.GameObjects; - -namespace Content.Client.Cargo; - -[RegisterComponent] -public sealed class CargoTelepadComponent : SharedCargoTelepadComponent -{ - -} diff --git a/Content.Client/Cargo/Systems/CargoSystem.Telepad.cs b/Content.Client/Cargo/Systems/CargoSystem.Telepad.cs index 6bc0f8800779ad..50d079737de01d 100644 --- a/Content.Client/Cargo/Systems/CargoSystem.Telepad.cs +++ b/Content.Client/Cargo/Systems/CargoSystem.Telepad.cs @@ -1,4 +1,6 @@ using Content.Shared.Cargo; +using Content.Shared.Cargo.Components; +using JetBrains.Annotations; using Robust.Client.Animations; using Robust.Client.GameObjects; using Robust.Client.Graphics; @@ -52,47 +54,48 @@ private void InitializeCargoTelepad() private void OnCargoAppChange(EntityUid uid, CargoTelepadComponent component, ref AppearanceChangeEvent args) { - OnChangeData(args.Component, args.Sprite); + OnChangeData(uid, args.Sprite); } private void OnCargoAnimComplete(EntityUid uid, CargoTelepadComponent component, AnimationCompletedEvent args) { - if (!TryComp(uid, out var appearance)) return; - - OnChangeData(appearance); + OnChangeData(uid); } - private void OnChangeData(AppearanceComponent component, SpriteComponent? sprite = null) + private void OnChangeData(EntityUid uid, SpriteComponent? sprite = null) { - if (!Resolve(component.Owner, ref sprite)) + if (!Resolve(uid, ref sprite)) return; - _appearance.TryGetData(component.Owner, CargoTelepadVisuals.State, out var state); + _appearance.TryGetData(uid, CargoTelepadVisuals.State, out var state); AnimationPlayerComponent? player = null; switch (state) { case CargoTelepadState.Teleporting: - if (_player.HasRunningAnimation(component.Owner, TelepadBeamKey)) return; - _player.Stop(component.Owner, player, TelepadIdleKey); - _player.Play(component.Owner, player, CargoTelepadBeamAnimation, TelepadBeamKey); + if (_player.HasRunningAnimation(uid, TelepadBeamKey)) + return; + _player.Stop(uid, player, TelepadIdleKey); + _player.Play(uid, player, CargoTelepadBeamAnimation, TelepadBeamKey); break; case CargoTelepadState.Unpowered: sprite.LayerSetVisible(CargoTelepadLayers.Beam, false); - _player.Stop(component.Owner, player, TelepadBeamKey); - _player.Stop(component.Owner, player, TelepadIdleKey); + _player.Stop(uid, player, TelepadBeamKey); + _player.Stop(uid, player, TelepadIdleKey); break; default: sprite.LayerSetVisible(CargoTelepadLayers.Beam, true); - if (_player.HasRunningAnimation(component.Owner, player, TelepadIdleKey) || - _player.HasRunningAnimation(component.Owner, player, TelepadBeamKey)) return; + if (_player.HasRunningAnimation(uid, player, TelepadIdleKey) || + _player.HasRunningAnimation(uid, player, TelepadBeamKey)) + return; - _player.Play(component.Owner, player, CargoTelepadIdleAnimation, TelepadIdleKey); + _player.Play(uid, player, CargoTelepadIdleAnimation, TelepadIdleKey); break; } } + [UsedImplicitly] private enum CargoTelepadLayers : byte { Base = 0, diff --git a/Content.Client/Cargo/UI/BountyEntry.xaml b/Content.Client/Cargo/UI/BountyEntry.xaml new file mode 100644 index 00000000000000..e570b03746a00f --- /dev/null +++ b/Content.Client/Cargo/UI/BountyEntry.xaml @@ -0,0 +1,27 @@ + + + + + + + + + + + + - - + + HorizontalExpand="True"> - - - - - + + + + + + + + + + + + + + + - - diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index fd3319c434faeb..7247db647bedd8 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -1,4 +1,6 @@ -using System.Text; +using System.Linq; +using System.Text; +using Content.Client.Stylesheets; using Content.Shared.Lathe; using Content.Shared.Materials; using Content.Shared.Research.Prototypes; @@ -21,7 +23,6 @@ public sealed partial class LatheMenu : DefaultWindow public event Action? OnQueueButtonPressed; public event Action? OnServerListButtonPressed; - public event Action? OnServerSyncButtonPressed; public event Action? RecipeQueueAction; public List Recipes = new(); @@ -48,15 +49,13 @@ public LatheMenu(LatheBoundUserInterface owner) QueueButton.OnPressed += a => OnQueueButtonPressed?.Invoke(a); ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a); - //refresh the bui state - ServerSyncButton.OnPressed += a => OnServerSyncButtonPressed?.Invoke(a); - if (_entityManager.TryGetComponent(owner.Lathe, out var latheComponent)) { - if (latheComponent.DynamicRecipes == null) + if (!latheComponent.DynamicRecipes.Any()) { ServerListButton.Visible = false; - ServerSyncButton.Visible = false; + QueueButton.RemoveStyleClass(StyleBase.ButtonOpenRight); + //QueueButton.AddStyleClass(StyleBase.ButtonSquare); } } } @@ -132,7 +131,7 @@ public void PopulateRecipes(EntityUid lathe) sb.Append('\n'); var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, component.MaterialUseMultiplier); - + sb.Append(adjustedAmount); sb.Append(' '); sb.Append(Loc.GetString(proto.Name)); diff --git a/Content.Client/Lathe/UI/RecipeControl.xaml b/Content.Client/Lathe/UI/RecipeControl.xaml index 5ef53421854185..cacbf84ff723b2 100644 --- a/Content.Client/Lathe/UI/RecipeControl.xaml +++ b/Content.Client/Lathe/UI/RecipeControl.xaml @@ -2,11 +2,13 @@