diff --git a/Content.Client/Voting/UI/VoteCallMenu.xaml.cs b/Content.Client/Voting/UI/VoteCallMenu.xaml.cs index 58c56ace4c..20c72ea0a9 100644 --- a/Content.Client/Voting/UI/VoteCallMenu.xaml.cs +++ b/Content.Client/Voting/UI/VoteCallMenu.xaml.cs @@ -25,7 +25,8 @@ namespace Content.Client.Voting.UI AvailableVoteTypes = { ("ui-vote-type-restart", StandardVoteType.Restart, null), - ("ui-vote-type-gamemode", StandardVoteType.Preset, null) + ("ui-vote-type-gamemode", StandardVoteType.Preset, null), + ("ui-vote-type-map", StandardVoteType.Map, null) }; public VoteCallMenu() diff --git a/Content.Server/GameTicking/Commands/ForceMapCommand.cs b/Content.Server/GameTicking/Commands/ForceMapCommand.cs new file mode 100644 index 0000000000..0738029d4a --- /dev/null +++ b/Content.Server/GameTicking/Commands/ForceMapCommand.cs @@ -0,0 +1,34 @@ +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.Console; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; + +namespace Content.Server.GameTicking.Commands +{ + [AdminCommand(AdminFlags.Server)] + class ForceMapCommand : IConsoleCommand + { + public string Command => "forcemap"; + public string Description => "forcemap-command-description"; + public string Help => $"forcemap-command-help"; + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length != 1) + { + shell.WriteLine(Loc.GetString("forcemap-command-need-one-argument")); + return; + } + + var cfg = IoCManager.Resolve(); + var name = args[0]; + + cfg.SetCVar(CCVars.GameMap, name); + shell.WriteLine(Loc.GetString("forcemap-command-success", ("map", name))); + } + } +} diff --git a/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs b/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs index 950a8134af..3901a66622 100644 --- a/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs +++ b/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs @@ -6,6 +6,7 @@ using Content.Shared.CCVar; using Content.Shared.Voting; using Robust.Server.Player; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Random; @@ -23,6 +24,9 @@ namespace Content.Server.Voting.Managers case StandardVoteType.Preset: CreatePresetVote(initiator); break; + case StandardVoteType.Map: + CreateMapVote(initiator); + break; default: throw new ArgumentOutOfRangeException(nameof(voteType), voteType, null); } @@ -140,6 +144,55 @@ namespace Content.Server.Voting.Managers }; } + private void CreateMapVote(IPlayerSession? initiator) + { + var maps = new Dictionary + { + ["Maps/saltern.yml"] = "Saltern", + ["Maps/packedstation.yml"] = "PackedStation", + }; + + var alone = _playerManager.PlayerCount == 1 && initiator != null; + var options = new VoteOptions + { + Title = Loc.GetString("ui-vote-map-title"), + Duration = alone + ? TimeSpan.FromSeconds(10) + : TimeSpan.FromSeconds(180) + }; + + if (alone) + options.InitiatorTimeout = TimeSpan.FromSeconds(10); + + foreach (var (k, v) in maps) + { + options.Options.Add((v, k)); + } + + WirePresetVoteInitiator(options, initiator); + + var vote = CreateVote(options); + + vote.OnFinished += (_, args) => + { + string picked; + if (args.Winner == null) + { + picked = (string) _random.Pick(args.Winners); + _chatManager.DispatchServerAnnouncement( + Loc.GetString("ui-vote-map-tie", ("picked", maps[picked]))); + } + else + { + picked = (string) args.Winner; + _chatManager.DispatchServerAnnouncement( + Loc.GetString("ui-vote-map-win", ("winner", maps[picked]))); + } + + _cfg.SetCVar(CCVars.GameMap, picked); + }; + } + private void TimeoutStandardVote(StandardVoteType type) { var timeout = TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.VoteSameTypeTimeout)); diff --git a/Content.Shared/Voting/StandardVoteType.cs b/Content.Shared/Voting/StandardVoteType.cs index d3d6e48db8..a0b33359ac 100644 --- a/Content.Shared/Voting/StandardVoteType.cs +++ b/Content.Shared/Voting/StandardVoteType.cs @@ -13,6 +13,11 @@ /// /// Vote to change the game preset for next round. /// - Preset + Preset, + + /// + /// Vote to change the map for the next round. + /// + Map } } diff --git a/Resources/Locale/en-US/game-ticking/forcemap-command.ftl b/Resources/Locale/en-US/game-ticking/forcemap-command.ftl new file mode 100644 index 0000000000..316eb21e8e --- /dev/null +++ b/Resources/Locale/en-US/game-ticking/forcemap-command.ftl @@ -0,0 +1,6 @@ +## Forcemap command loc. + +forcemap-command-description = Forces the game to start with a given map next round. +forcemap-command-help = forcemap +forcemap-command-need-one-argument = forcemap takes one argument, the path to the map file. +forcemap-command-success = Forced the game to start with map { $map } next round. diff --git a/Resources/Locale/en-US/voting/managers/vote-manager.ftl b/Resources/Locale/en-US/voting/managers/vote-manager.ftl index c5e7e09cda..2f349acfe3 100644 --- a/Resources/Locale/en-US/voting/managers/vote-manager.ftl +++ b/Resources/Locale/en-US/voting/managers/vote-manager.ftl @@ -13,7 +13,11 @@ ui-vote-gamemode-title = Next gamemode ui-vote-gamemode-tie = Tie for gamemode vote! Picking... { $picked } ui-vote-gamemode-win = { $winner } won the gamemode vote! +ui-vote-map-title = Next map +ui-vote-map-tie = Tie for map vote! Picking... { $picked } +ui-vote-map-win = { $winner } won the map vote! + mode-traitor = Traitor mode-extended = Extended mode-sandbox = Sandbox -mode-suspicion = Suspicion \ No newline at end of file +mode-suspicion = Suspicion diff --git a/Resources/Locale/en-US/voting/ui/vote-call-menu.ftl b/Resources/Locale/en-US/voting/ui/vote-call-menu.ftl index 1e9fefc2c9..293f890bfc 100644 --- a/Resources/Locale/en-US/voting/ui/vote-call-menu.ftl +++ b/Resources/Locale/en-US/voting/ui/vote-call-menu.ftl @@ -1,5 +1,6 @@ ui-vote-type-restart = Restart round ui-vote-type-gamemode = Next gamemode +ui-vote-type-map = Next map # Window title of the vote create menu ui-vote-create-title = Call Vote