diff --git a/Content.Client/ClientContentIoC.cs b/Content.Client/ClientContentIoC.cs index 8639ea4c24..e7d8d90841 100644 --- a/Content.Client/ClientContentIoC.cs +++ b/Content.Client/ClientContentIoC.cs @@ -7,6 +7,7 @@ using Content.Client.Parallax; using Content.Client.Sandbox; using Content.Client.StationEvents; using Content.Client.UserInterface; +using Content.Client.UserInterface.AdminMenu; using Content.Client.UserInterface.Stylesheets; using Content.Client.Utility; using Content.Shared.Interfaces; @@ -33,6 +34,7 @@ namespace Content.Client IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); } } } diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 912440baac..a4edb0736c 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -9,6 +9,7 @@ using Content.Client.Sandbox; using Content.Client.State; using Content.Client.StationEvents; using Content.Client.UserInterface; +using Content.Client.UserInterface.AdminMenu; using Content.Client.UserInterface.Stylesheets; using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components.Cargo; @@ -150,6 +151,7 @@ namespace Content.Client IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); + IoCManager.Resolve().Initialize(); _baseClient.RunLevelChanged += (sender, args) => { diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 89ddd64268..26834dfd16 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -50,6 +50,7 @@ namespace Content.Client.Input common.AddFunction(ContentKeyFunctions.OpenEntitySpawnWindow); common.AddFunction(ContentKeyFunctions.OpenSandboxWindow); common.AddFunction(ContentKeyFunctions.OpenTileSpawnWindow); + common.AddFunction(ContentKeyFunctions.OpenAdminMenu); } } } diff --git a/Content.Client/StationEvents/IStationEventManager.cs b/Content.Client/StationEvents/IStationEventManager.cs index 828b20e80d..3381708f6a 100644 --- a/Content.Client/StationEvents/IStationEventManager.cs +++ b/Content.Client/StationEvents/IStationEventManager.cs @@ -9,5 +9,6 @@ namespace Content.Client.StationEvents public List? StationEvents { get; } public void Initialize(); public event Action OnStationEventsReceived; + public void RequestEvents(); } } diff --git a/Content.Client/UserInterface/AdminMenu/AdminMenuManager.cs b/Content.Client/UserInterface/AdminMenu/AdminMenuManager.cs new file mode 100644 index 0000000000..596d47e9ef --- /dev/null +++ b/Content.Client/UserInterface/AdminMenu/AdminMenuManager.cs @@ -0,0 +1,103 @@ +using Content.Shared.Input; +using Robust.Client.Console; +using Robust.Client.Interfaces.Input; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.Input.Binding; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.IoC; +using System.Collections.Generic; + +namespace Content.Client.UserInterface.AdminMenu +{ + internal class AdminMenuManager : IAdminMenuManager + { + [Dependency] private INetManager _netManager = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly IClientConGroupController _clientConGroupController = default!; + + private SS14Window _window; + private List _commandWindows; + + public void Initialize() + { + _commandWindows = new List(); + // Reset the AdminMenu Window on disconnect + _netManager.Disconnect += (sender, channel) => ResetWindow(); + + _inputManager.SetInputCommand(ContentKeyFunctions.OpenAdminMenu, + InputCmdHandler.FromDelegate(session => Toggle())); + } + + public void ResetWindow() + { + _window?.Close(); + _window = null; + + foreach (var window in _commandWindows) + window?.Dispose(); + _commandWindows.Clear(); + } + + public void OpenCommand(SS14Window window) + { + _commandWindows.Add(window); + window.OpenCentered(); + } + + public void Open() + { + if (_window == null) + _window = new AdminMenuWindow(); + _window.OpenCentered(); + } + + public void Close() + { + _window?.Close(); + + foreach (var window in _commandWindows) + window?.Dispose(); + _commandWindows.Clear(); + } + + /// + /// Checks if the player can open the window + /// + /// True if the player is allowed + public bool CanOpen() + { + return _clientConGroupController.CanAdminMenu(); + } + + /// + /// Checks if the player can open the window and tries to open it + /// + public void TryOpen() + { + if (CanOpen()) + Open(); + } + + public void Toggle() + { + if (_window != null && _window.IsOpen) + { + Close(); + } + else + { + TryOpen(); + } + } + } + + internal interface IAdminMenuManager + { + void Initialize(); + void Open(); + void OpenCommand(SS14Window window); + bool CanOpen(); + void TryOpen(); + void Toggle(); + } +} diff --git a/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs b/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs new file mode 100644 index 0000000000..3708adfb82 --- /dev/null +++ b/Content.Client/UserInterface/AdminMenu/AdminMenuWindow.cs @@ -0,0 +1,670 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Linq; +using Content.Client.GameObjects.EntitySystems; +using Content.Client.StationEvents; +using Content.Shared.Atmos; +using Robust.Client.Console; +using Robust.Client.Interfaces.Placement; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.Player; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.Map; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using static Robust.Client.UserInterface.Controls.BaseButton; + +namespace Content.Client.UserInterface.AdminMenu +{ + public class AdminMenuWindow : SS14Window + { + public TabContainer MasterTabContainer; + public VBoxContainer PlayerList; + + private List _adminButtons = new List + { + new KickCommandButton(), + new DirectCommandButton("Admin Ghost", "aghost"), + //TODO: teleport + }; + private List _adminbusButtons = new List + { + new SpawnEntitiesCommandButton(), + new SpawnTilesCommandButton(), + new StationEventsCommandButton(), + }; + private List _debugButtons = new List + { + new AddAtmosCommandButton(), + new FillGasCommandButton(), + }; + private List _roundButtons = new List + { + new DirectCommandButton("Start Round", "startround"), + new DirectCommandButton("End Round", "endround"), + new DirectCommandButton("Restart Round", "restartround"), + }; + private List _serverButtons = new List + { + new DirectCommandButton("Reboot", "restart"), + new DirectCommandButton("Shutdown", "shutdown"), + }; + + private void RefreshPlayerList(ButtonEventArgs args) + { + PlayerList.RemoveAllChildren(); + var sessions = IoCManager.Resolve().Sessions; + var header = new HBoxContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + Children = + { + new Label { Text = "Name", + SizeFlagsStretchRatio = 2f, + SizeFlagsHorizontal = SizeFlags.FillExpand }, + new Label { Text = "Player", + SizeFlagsStretchRatio = 2f, + SizeFlagsHorizontal = SizeFlags.FillExpand }, + new Label { Text = "Status", + SizeFlagsStretchRatio = 1f, + SizeFlagsHorizontal = SizeFlags.FillExpand }, + new Label { Text = "Ping", + SizeFlagsStretchRatio = 1f, + SizeFlagsHorizontal = SizeFlags.FillExpand, + Align = Label.AlignMode.Right }, + } + }; + PlayerList.AddChild(header); + PlayerList.AddChild(new Controls.HighDivider()); + foreach (var player in sessions) + { + var hbox = new HBoxContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + Children = + { + new Label { + Text = player.Name, + SizeFlagsStretchRatio = 2f, + SizeFlagsHorizontal = SizeFlags.FillExpand }, + new Label { + Text = player.AttachedEntity?.Name, + SizeFlagsStretchRatio = 2f, + SizeFlagsHorizontal = SizeFlags.FillExpand }, + new Label { + Text = player.Status.ToString(), + SizeFlagsStretchRatio = 1f, + SizeFlagsHorizontal = SizeFlags.FillExpand }, + new Label { + Text = player.Ping.ToString(), + SizeFlagsStretchRatio = 1f, + SizeFlagsHorizontal = SizeFlags.FillExpand, + Align = Label.AlignMode.Right }, + } + }; + PlayerList.AddChild(hbox); + } + } + + private void AddCommandButton(List buttons, Control parent) + { + foreach (var cmd in buttons) + { + // Check if the player can do the command + if (!cmd.CanPress()) + continue; + + //TODO: make toggle? + var button = new Button + { + Text = cmd.Name + }; + button.OnPressed += cmd.ButtonPressed; + parent.AddChild(button); + } + } + + public AdminMenuWindow() //TODO: search for buttons? + { + CustomMinimumSize = (415,0); + Title = Loc.GetString("Admin Menu"); + + #region PlayerList + // Players // List of all the players, their entities and status + var playerTabContainer = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 4, + MarginRightOverride = 4, + MarginBottomOverride = 4, + CustomMinimumSize = (50, 50), + }; + PlayerList = new VBoxContainer(); + var refreshButton = new Button + { + Text = "Refresh" + }; + refreshButton.OnPressed += RefreshPlayerList; + RefreshPlayerList(null!); + var playerVBox = new VBoxContainer + { + Children = + { + refreshButton, + PlayerList + } + }; + playerTabContainer.AddChild(playerVBox); + #endregion PlayerList + + #region Admin Tab + // Admin Tab // Actual admin stuff + var adminTabContainer = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 4, + MarginRightOverride = 4, + MarginBottomOverride = 4, + CustomMinimumSize = (50, 50), + }; + var adminButtonGrid = new GridContainer + { + Columns = 4, + }; + AddCommandButton(_adminButtons, adminButtonGrid); + adminTabContainer.AddChild(adminButtonGrid); + #endregion + + #region Adminbus + // Adminbus // Fun Commands + var adminbusTabContainer = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 4, + MarginRightOverride = 4, + MarginBottomOverride = 4, + CustomMinimumSize = (50, 50), + }; + var adminbusButtonGrid = new GridContainer + { + Columns = 4, + }; + AddCommandButton(_adminbusButtons, adminbusButtonGrid); + adminbusTabContainer.AddChild(adminbusButtonGrid); + #endregion + + #region Debug + // Debug // Mostly dev tools, like addatmos + var debugTabContainer = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 4, + MarginRightOverride = 4, + MarginBottomOverride = 4, + CustomMinimumSize = (50, 50), + }; + var debugButtonGrid = new GridContainer + { + Columns = 4, + }; + AddCommandButton(_debugButtons, debugButtonGrid); + debugTabContainer.AddChild(debugButtonGrid); + #endregion + + #region Round + // Round // Commands like Check Antags, End Round, RestartRound + var roundTabContainer = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 4, + MarginRightOverride = 4, + MarginBottomOverride = 4, + CustomMinimumSize = (50, 50), + }; + var roundButtonGrid = new GridContainer + { + Columns = 4, + }; + AddCommandButton(_roundButtons, roundButtonGrid); + roundTabContainer.AddChild(roundButtonGrid); + #endregion + + #region Server + // Server // Commands like Restart, Shutdown + var serverTabContainer = new MarginContainer + { + MarginLeftOverride = 4, + MarginTopOverride = 4, + MarginRightOverride = 4, + MarginBottomOverride = 4, + CustomMinimumSize = (50, 50), + }; + var serverButtonGrid = new GridContainer + { + Columns = 4, + }; + AddCommandButton(_serverButtons, serverButtonGrid); + serverTabContainer.AddChild(serverButtonGrid); + #endregion + + + //The master menu that contains all of the tabs. + MasterTabContainer = new TabContainer(); + + //Add all the tabs to the Master container. + MasterTabContainer.AddChild(adminTabContainer); + MasterTabContainer.SetTabTitle(0, Loc.GetString("Admin")); + MasterTabContainer.AddChild(adminbusTabContainer); + MasterTabContainer.SetTabTitle(1, Loc.GetString("Adminbus")); + MasterTabContainer.AddChild(debugTabContainer); + MasterTabContainer.SetTabTitle(2, Loc.GetString("Debug")); + MasterTabContainer.AddChild(roundTabContainer); + MasterTabContainer.SetTabTitle(3, Loc.GetString("Round")); + MasterTabContainer.AddChild(serverTabContainer); + MasterTabContainer.SetTabTitle(4, Loc.GetString("Server")); + MasterTabContainer.AddChild(playerTabContainer); + MasterTabContainer.SetTabTitle(5, Loc.GetString("Players")); + Contents.AddChild(MasterTabContainer); + //Request station events, so we can use them later + IoCManager.Resolve().RequestEvents(); + } + + #region CommandButtonBaseClass + private abstract class CommandButton + { + public virtual string Name { get; } + public virtual string RequiredCommand { get; } + public abstract void ButtonPressed(ButtonEventArgs args); + public virtual bool CanPress() + { + return RequiredCommand == string.Empty || + IoCManager.Resolve().CanCommand(RequiredCommand); + } + + public CommandButton() : this(string.Empty, string.Empty) {} + public CommandButton(string name, string command) + { + Name = name; + RequiredCommand = command; + } + } + + // Button that opens a UI + private abstract class UICommandButton : CommandButton + { + // The text on the submit button + public virtual string? SubmitText { get; } + /// + /// Called when the Submit button is pressed + /// + /// Dictionary of the parameter names and values + public abstract void Submit(); + public override void ButtonPressed(ButtonEventArgs args) + { + var manager = IoCManager.Resolve(); + var window = new CommandWindow(this); + window.Submit += Submit; + manager.OpenCommand(window); + } + // List of all the UI Elements + public abstract List UI { get; } + } + + // Button that directly calls a Command + private class DirectCommandButton : CommandButton + { + public DirectCommandButton(string name, string command) : base(name, command) { } + + public override void ButtonPressed(ButtonEventArgs args) + { + IoCManager.Resolve().ProcessCommand(RequiredCommand); + } + } + #endregion + + #region CommandButtons + private class SpawnEntitiesCommandButton : CommandButton + { + public override string Name => "Spawn Entities"; + //TODO: override CanPress + public override void ButtonPressed(ButtonEventArgs args) + { + var manager = IoCManager.Resolve(); + var window = new EntitySpawnWindow(IoCManager.Resolve(), + IoCManager.Resolve(), + IoCManager.Resolve(), + IoCManager.Resolve()); + manager.OpenCommand(window); + } + } + + private class SpawnTilesCommandButton : CommandButton + { + public override string Name => "Spawn Tiles"; + //TODO: override CanPress + public override void ButtonPressed(ButtonEventArgs args) + { + var manager = IoCManager.Resolve(); + var window = new TileSpawnWindow(IoCManager.Resolve(), + IoCManager.Resolve(), + IoCManager.Resolve()); + manager.OpenCommand(window); + } + } + + private class StationEventsCommandButton : UICommandButton + { + public override string Name => "Station Events"; + public override string RequiredCommand => "events"; + public override string? SubmitText => "Run"; + + private CommandUIDropDown _eventsDropDown = new CommandUIDropDown + { + Name = "Event", + GetData = () => + { + var events = IoCManager.Resolve().StationEvents; + if (events == null) + return new List { "Not loaded" }; + events.Add("Random"); + return events.ToList(); + }, + GetDisplayName = (obj) => (string) obj, + GetValueFromData = (obj) => ((string) obj).ToLower(), + }; + + public override List UI => new List + { + _eventsDropDown, + new CommandUIButton + { + Name = "Pause", + Handler = () => + { + IoCManager.Resolve().ProcessCommand($"events pause"); + }, + }, + new CommandUIButton + { + Name = "Resume", + Handler = () => + { + IoCManager.Resolve().ProcessCommand($"events resume"); + }, + }, + }; + + public override void Submit() + { + IoCManager.Resolve().ProcessCommand($"events run \"{_eventsDropDown.GetValue()}\""); + } + } + + private class KickCommandButton : UICommandButton + { + public override string Name => "Kick"; + public override string RequiredCommand => "kick"; + + private CommandUIDropDown _playerDropDown = new CommandUIDropDown + { + Name = "Player", + GetData = () => IoCManager.Resolve().Sessions.ToList(), + GetDisplayName = (obj) => $"{((IPlayerSession) obj).Name} ({((IPlayerSession) obj).AttachedEntity?.Name})", + GetValueFromData = (obj) => ((IPlayerSession) obj).Name, + }; + private CommandUILineEdit _reason = new CommandUILineEdit + { + Name = "Reason" + }; + + public override List UI => new List + { + _playerDropDown, + _reason + }; + + public override void Submit() + { + IoCManager.Resolve().ProcessCommand($"kick \"{_playerDropDown.GetValue()}\" \"{CommandParsing.Escape(_reason.GetValue())}\""); + } + } + + private class AddAtmosCommandButton : UICommandButton + { + public override string Name => "Add Atmos"; + public override string RequiredCommand => "addatmos"; + + private CommandUIDropDown _grid = new CommandUIDropDown + { + Name = "Grid", + GetData = () => IoCManager.Resolve().GetAllGrids().Where(g => (int) g.Index != 0).ToList(), + GetDisplayName = (obj) => $"{((IMapGrid) obj).Index}{(IoCManager.Resolve().LocalPlayer?.ControlledEntity?.Transform.GridID == ((IMapGrid) obj).Index ? " (Current)" : "")}", + GetValueFromData = (obj) => ((IMapGrid) obj).Index.ToString(), + }; + + public override List UI => new List + { + _grid, + }; + + public override void Submit() + { + IoCManager.Resolve().ProcessCommand($"addatmos {_grid.GetValue()}"); + } + } + + private class FillGasCommandButton : UICommandButton + { + public override string Name => "Fill Gas"; + public override string RequiredCommand => "fillgas"; + + private CommandUIDropDown _grid = new CommandUIDropDown + { + Name = "Grid", + GetData = () => IoCManager.Resolve().GetAllGrids().Where(g => (int) g.Index != 0).ToList(), + GetDisplayName = (obj) => $"{((IMapGrid) obj).Index}{(IoCManager.Resolve().LocalPlayer?.ControlledEntity?.Transform.GridID == ((IMapGrid) obj).Index ? " (Current)" : "")}", + GetValueFromData = (obj) => ((IMapGrid) obj).Index.ToString(), + }; + + private CommandUIDropDown _gas = new CommandUIDropDown + { + Name = "Gas", + GetData = () => + { + var atmosSystem = EntitySystem.Get(); + return atmosSystem.Gases.ToList(); + }, + GetDisplayName = (obj) => $"{((GasPrototype) obj).Name} ({((GasPrototype) obj).ID})", + GetValueFromData = (obj) => ((GasPrototype) obj).ID.ToString(), + }; + + private CommandUISpinBox _amount = new CommandUISpinBox + { + Name = "Amount" + }; + + public override List UI => new List + { + _grid, + _gas, + _amount, + }; + + public override void Submit() + { + IoCManager.Resolve().ProcessCommand($"fillgas {_grid.GetValue()} {_gas.GetValue()} {_amount.GetValue()}"); + } + } + #endregion + + #region CommandUIControls + private abstract class CommandUIControl + { + public string? Name; + public Control? Control; + public abstract Control GetControl(); + public abstract string GetValue(); + } + private class CommandUIDropDown : CommandUIControl + { + public Func>? GetData; + // The string that the player sees in the list + public Func? GetDisplayName; + // The value that is given to Submit + public Func? GetValueFromData; + // Cache + protected List? Data; //TODO: make this like IEnumerable or smth, so you don't have to do this ToList shittery + + public override Control GetControl() //TODO: fix optionbutton being shitty after moving the window + { + var opt = new OptionButton { CustomMinimumSize = (100, 0), SizeFlagsHorizontal = SizeFlags.FillExpand }; + Data = GetData!(); + foreach (var item in Data) + opt.AddItem(GetDisplayName!(item)); + + opt.OnItemSelected += eventArgs => opt.SelectId(eventArgs.Id); + Control = opt; + return Control; + } + + public override string GetValue() + { + return GetValueFromData!(Data![((OptionButton)Control!).SelectedId]); + } + } + private class CommandUICheckBox : CommandUIControl + { + public override Control GetControl() + { + Control = new CheckBox { SizeFlagsHorizontal = SizeFlags.FillExpand, SizeFlagsVertical = SizeFlags.ShrinkCenter }; + return Control; + } + + public override string GetValue() + { + return ((CheckBox)Control!).Pressed ? "1" : "0"; + } + } + private class CommandUILineEdit : CommandUIControl + { + public override Control GetControl() + { + Control = new LineEdit { CustomMinimumSize = (100, 0), SizeFlagsHorizontal = SizeFlags.FillExpand }; + return Control; + } + + public override string GetValue() + { + return ((LineEdit)Control!).Text; + } + } + + private class CommandUISpinBox : CommandUIControl + { + public override Control GetControl() + { + Control = new SpinBox { CustomMinimumSize = (100, 0), SizeFlagsHorizontal = SizeFlags.FillExpand }; + return Control; + } + + public override string GetValue() + { + return ((SpinBox)Control!).Value.ToString(); + } + } + + private class CommandUIButton : CommandUIControl + { + public Action? Handler { get; set; } + + public override Control GetControl() + { + Control = new Button { + CustomMinimumSize = (100, 0), + SizeFlagsHorizontal = SizeFlags.FillExpand, + Text = Name }; + return Control; + } + + public override string GetValue() + { + return ""; + } + } + #endregion + + #region CommandWindow + private class CommandWindow : SS14Window + { + List _controls; + public Action? Submit { get; set; } + public CommandWindow(UICommandButton button) + { + Title = button.Name; + _controls = button.UI; + var container = new VBoxContainer //TODO: add margin between different controls + { + }; + // Init Controls in a hbox + a label + foreach (var control in _controls) + { + var c = control.GetControl(); + if (c is Button) + { + ((Button) c).OnPressed += (args) => + { + ((CommandUIButton) control).Handler?.Invoke(); + }; + container.AddChild(c); + } + else + { + var label = new Label + { + Text = control.Name, + CustomMinimumSize = (100, 0) + }; + var divider = new Control + { + CustomMinimumSize = (50, 0) + }; + var hbox = new HBoxContainer + { + Children = + { + label, + divider, + c + }, + }; + container.AddChild(hbox); + } + + + } + // Init Submit Button + var submitButton = new Button + { + Text = button.SubmitText ?? button.Name + }; + submitButton.OnPressed += SubmitPressed; + container.AddChild(submitButton); + + Contents.AddChild(container); + } + + public void SubmitPressed(ButtonEventArgs args) + { + Submit?.Invoke(); + } + } + #endregion + } +} diff --git a/Content.Client/UserInterface/TutorialWindow.cs b/Content.Client/UserInterface/TutorialWindow.cs index 6e4b90f1d6..606f3ff2b3 100644 --- a/Content.Client/UserInterface/TutorialWindow.cs +++ b/Content.Client/UserInterface/TutorialWindow.cs @@ -92,7 +92,8 @@ Toggle UI: [color=#a4885c]{17}[/color] Toggle debug overlay: [color=#a4885c]{18}[/color] Toggle entity spawner: [color=#a4885c]{19}[/color] Toggle tile spawner: [color=#a4885c]{20}[/color] -Toggle sandbox window: [color=#a4885c]{21}[/color]", +Toggle sandbox window: [color=#a4885c]{21}[/color] +Toggle admin menu [color=#a4885c]{31}[/color]", Key(MoveUp), Key(MoveLeft), Key(MoveDown), Key(MoveRight), Key(SwapHands), Key(ActivateItemInHand), @@ -120,7 +121,8 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]", Key(FocusAdminChat), Key(Point), Key(TryPullObject), - Key(MovePulledObject))); + Key(MovePulledObject), + Key(OpenAdminMenu))); //Gameplay VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" }); diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index 5cf834bea3..e0a1bc62c6 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -29,6 +29,7 @@ namespace Content.Shared.Input public static readonly BoundKeyFunction OpenEntitySpawnWindow = "OpenEntitySpawnWindow"; public static readonly BoundKeyFunction OpenSandboxWindow = "OpenSandboxWindow"; public static readonly BoundKeyFunction OpenTileSpawnWindow = "OpenTileSpawnWindow"; + public static readonly BoundKeyFunction OpenAdminMenu = "OpenAdminMenu"; public static readonly BoundKeyFunction TakeScreenshot = "TakeScreenshot"; public static readonly BoundKeyFunction TakeScreenshotNoUI = "TakeScreenshotNoUI"; public static readonly BoundKeyFunction Point = "Point"; diff --git a/Resources/Groups/groups.yml b/Resources/Groups/groups.yml index 75fe17e4bf..e7120fce27 100644 --- a/Resources/Groups/groups.yml +++ b/Resources/Groups/groups.yml @@ -38,6 +38,7 @@ - hostlogin - events - factions + CanAdminMenu: true - Index: 100 Name: Administrator @@ -102,6 +103,7 @@ - factions CanViewVar: true CanAdminPlace: true + CanAdminMenu: true - Index: 200 Name: Host @@ -196,3 +198,4 @@ CanViewVar: true CanAdminPlace: true CanScript: true + CanAdminMenu: true diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 2431c3f3c9..01357c28e0 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -248,6 +248,9 @@ binds: - function: OpenTileSpawnWindow type: state key: F6 +- function: OpenAdminMenu + type: state + key: F7 - function: OpenSandboxWindow type: state key: B