diff --git a/Content.Client/Administration/UI/Tabs/AdminTab/AdminShuttleWindow.xaml b/Content.Client/Administration/UI/Tabs/AdminTab/AdminShuttleWindow.xaml new file mode 100644 index 0000000000..316c79ddf1 --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/AdminTab/AdminShuttleWindow.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/Content.Client/Administration/UI/Tabs/AdminTab/AdminShuttleWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/AdminTab/AdminShuttleWindow.xaml.cs new file mode 100644 index 0000000000..be81895f4d --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/AdminTab/AdminShuttleWindow.xaml.cs @@ -0,0 +1,31 @@ +using System; +using Content.Shared.Localizations; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Client.Administration.UI.Tabs.AdminTab +{ + [GenerateTypedNameReferences] + public partial class AdminShuttleWindow : SS14Window + { + public AdminShuttleWindow() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + _callShuttleTime.OnTextChanged += CallShuttleTimeOnOnTextChanged; + } + + private void CallShuttleTimeOnOnTextChanged(LineEdit.LineEditEventArgs obj) + { + var loc = IoCManager.Resolve(); + _callShuttleButton.Disabled = !TimeSpan.TryParseExact(obj.Text, Localization.TimeSpanMinutesFormats, loc.DefaultCulture, out _); + _callShuttleButton.Command = $"callshuttle {obj.Text}"; + } + } +} diff --git a/Content.Client/Administration/UI/Tabs/AdminTab/AdminTab.xaml b/Content.Client/Administration/UI/Tabs/AdminTab/AdminTab.xaml index da899fe580..c6660a64e8 100644 --- a/Content.Client/Administration/UI/Tabs/AdminTab/AdminTab.xaml +++ b/Content.Client/Administration/UI/Tabs/AdminTab/AdminTab.xaml @@ -6,13 +6,14 @@ Margin="4" MinSize="50 50"> - + + diff --git a/Content.Server/Administration/Commands/ShuttleCommands.cs b/Content.Server/Administration/Commands/ShuttleCommands.cs new file mode 100644 index 0000000000..6e409eced1 --- /dev/null +++ b/Content.Server/Administration/Commands/ShuttleCommands.cs @@ -0,0 +1,51 @@ +using System; +using Content.Server.RoundEnd; +using Content.Shared.Administration; +using Content.Shared.Localizations; +using Robust.Shared.Console; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Server.Administration.Commands +{ + [AdminCommand(AdminFlags.Server)] + public class CallShuttleCommand : IConsoleCommand + { + public string Command => "callshuttle"; + public string Description => Loc.GetString("call-shuttle-command-description"); + public string Help => Loc.GetString("call-shuttle-command-help-text", ("command",Command)); + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + var loc = IoCManager.Resolve(); + + // ReSharper disable once ConvertIfStatementToSwitchStatement + if (args.Length == 1 && TimeSpan.TryParseExact(args[0], Localization.TimeSpanMinutesFormats, loc.DefaultCulture, out var timeSpan)) + { + EntitySystem.Get().RequestRoundEnd(timeSpan, false); + } + else if (args.Length == 1) + { + shell.WriteLine(Loc.GetString("shell-timespan-minutes-must-be-correct")); + } + else + { + EntitySystem.Get().RequestRoundEnd(false); + } + } + } + + [AdminCommand(AdminFlags.Server)] + public class RecallShuttleCommand : IConsoleCommand + { + public string Command => "recallshuttle"; + public string Description => Loc.GetString("recall-shuttle-command-description"); + public string Help => Loc.GetString("recall-shuttle-command-help-text", ("command",Command)); + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + EntitySystem.Get().CancelRoundEndCountdown(false); + } + } +} diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index c1164ac85f..1486c1779a 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -74,36 +74,41 @@ namespace Content.Server.RoundEnd Timer.Spawn(CallCooldown, () => OnCallCooldownEnded?.Invoke(), _callCooldownEndedTokenSource.Token); } - public void RequestRoundEnd() + public void RequestRoundEnd(bool checkCooldown = true) + { + RequestRoundEnd(RoundEndCountdownTime, checkCooldown); + } + + public void RequestRoundEnd(TimeSpan countdownTime, bool checkCooldown = true) { if (IsRoundEndCountdownStarted) return; - if (!CanCall()) + if (checkCooldown && !CanCall()) { return; } IsRoundEndCountdownStarted = true; - _chatManager.DispatchStationAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement",("minutes", RoundEndCountdownTime.Minutes)), Loc.GetString("Station")); + _chatManager.DispatchStationAnnouncement(Loc.GetString("round-end-system-shuttle-called-announcement",("minutes", countdownTime.Minutes)), Loc.GetString("Station")); SoundSystem.Play(Filter.Broadcast(), "/Audio/Announcements/shuttlecalled.ogg"); - ExpectedCountdownEnd = _gameTiming.CurTime + RoundEndCountdownTime; - Timer.Spawn(RoundEndCountdownTime, EndRound, _roundEndCancellationTokenSource.Token); + ExpectedCountdownEnd = _gameTiming.CurTime + countdownTime; + Timer.Spawn(countdownTime, EndRound, _roundEndCancellationTokenSource.Token); ActivateCooldown(); OnRoundEndCountdownStarted?.Invoke(); } - public void CancelRoundEndCountdown() + public void CancelRoundEndCountdown( bool checkCooldown = true) { if (!IsRoundEndCountdownStarted) return; - if (!CanCall()) + if (checkCooldown && !CanCall()) { return; } diff --git a/Content.Shared/Localizations/Localization.cs b/Content.Shared/Localizations/Localization.cs index bca3172c47..cbdbd0868b 100644 --- a/Content.Shared/Localizations/Localization.cs +++ b/Content.Shared/Localizations/Localization.cs @@ -11,6 +11,17 @@ namespace Content.Shared.Localizations // If you want to change your codebase's language, do it here. private const string Culture = "en-US"; + /// + /// Custom format strings used for parsing and displaying minutes:seconds timespans. + /// + public static readonly string[] TimeSpanMinutesFormats = new[] + { + @"m\:ss", + @"mm\:ss", + @"%m", + @"mm" + }; + public static void Init() { var loc = IoCManager.Resolve(); diff --git a/Resources/Locale/en-US/administration/commands/call-shuttle-command.ftl b/Resources/Locale/en-US/administration/commands/call-shuttle-command.ftl new file mode 100644 index 0000000000..672c68fd7c --- /dev/null +++ b/Resources/Locale/en-US/administration/commands/call-shuttle-command.ftl @@ -0,0 +1,4 @@ +call-shuttle-command-description = Calls the emergency shuttle with an optionally provided arrival time. +call-shuttle-command-help-text = Usage: {$command} [m:ss] +recall-shuttle-command-description = Recalls the emergency shuttle. +recall-shuttle-command-help-text = Usage: {$command} diff --git a/Resources/Locale/en-US/administration/ui/tabs/admin-tab/call-shuttle-window.ftl b/Resources/Locale/en-US/administration/ui/tabs/admin-tab/call-shuttle-window.ftl new file mode 100644 index 0000000000..14a790f81a --- /dev/null +++ b/Resources/Locale/en-US/administration/ui/tabs/admin-tab/call-shuttle-window.ftl @@ -0,0 +1 @@ +admin-shuttle-title = (Re)call shuttle diff --git a/Resources/Locale/en-US/shell.ftl b/Resources/Locale/en-US/shell.ftl index b8fe21d26b..ee3d6d7fff 100644 --- a/Resources/Locale/en-US/shell.ftl +++ b/Resources/Locale/en-US/shell.ftl @@ -6,7 +6,7 @@ shell-server-cannot = Server cannot do this. shell-command-success = Command successful shell-invalid-command = Invalid command. shell-invalid-command-specific = Invalid {$commandName} command. -shell-cannot-run-command-from-server = You cannot run this command from the server. +shell-cannot-run-command-from-server = You cannot run this command from the server. shell-only-players-can-run-this-command = Only players can run this command. ## Arguments @@ -29,5 +29,4 @@ shell-entity-with-uid-lacks-component = Entity with uid {$uid} doesn't have a {$ shell-invalid-color-hex = Invalid color hex! shell-target-player-does-not-exist = Target player does not exist! shell-target-entity-does-not-have-message = Target entity does not have a(n) {$missing}! - - +shell-timespan-minutes-must-be-correct = {$span} is not a valid minutes timespan.