diff --git a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs index 8b3de02d03..67a10b0a20 100644 --- a/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs +++ b/OpenRA.Mods.RA/ServerTraits/LobbyCommands.cs @@ -335,46 +335,35 @@ namespace OpenRA.Mods.RA.Server return true; } - int teams; - if (!int.TryParse(s, out teams)) + int teamCount; + if (!int.TryParse(s, out teamCount)) { server.SendOrderTo(conn, "Message", "Number of teams could not be parsed: {0}".F(s)); return true; } - teams = teams.Clamp(1, 8); + var maxTeams = (server.lobbyInfo.Clients.Count(c => c.Slot != null) + 1) / 2; + teamCount = teamCount.Clamp(0, maxTeams); var players = server.lobbyInfo.Slots - .Select(slot => server.lobbyInfo.Clients.SingleOrDefault(c => c.Slot == slot.Key)) - .Where(c => c != null && !server.lobbyInfo.Slots[c.Slot].LockTeam).ToArray(); - if (players.Length < 2) + .Select(slot => server.lobbyInfo.ClientInSlot(slot.Key)) + .Where(c => c != null && !server.lobbyInfo.Slots[c.Slot].LockTeam); + + var assigned = 0; + var playerCount = players.Count(); + foreach (var player in players) { - server.SendOrderTo(conn, "Message", "Not enough players to assign teams"); - return true; - } - if (teams > players.Length) - { - server.SendOrderTo(conn, "Message", "Too many teams for the number of players"); - return true; + // Free for all + if (teamCount == 0) + player.Team = 0; + + // Humans vs Bots + else if (teamCount == 1) + player.Team = player.Bot == null ? 1 : 2; + + else + player.Team = assigned++ * teamCount / playerCount + 1; } - var teamSizes = new int[players.Length]; - for (var i = 0; i < players.Length; i++) - teamSizes[i % teams]++; - - var playerIndex = 0; - for (var team = 1; team <= teams; team++) - { - for (var teamPlayerIndex = 0; teamPlayerIndex < teamSizes[team - 1]; playerIndex++, teamPlayerIndex++) - { - var cl = players[playerIndex]; - if (cl.Bot == null) - cl.State = Session.ClientState.NotReady; - cl.Team = team; - } - } - // All vs Host - if (teams == 1) - client.Team = 2; server.SyncLobbyInfo(); return true; }}, diff --git a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs index 98bf8efa85..1a36f38529 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/LobbyLogic.cs @@ -165,49 +165,83 @@ namespace OpenRA.Mods.RA.Widgets.Logic }; mapButton.IsVisible = () => mapButton.Visible && Game.IsHost; - var assignTeams = lobby.GetOrNull("ASSIGNTEAMS_DROPDOWNBUTTON"); - if (assignTeams != null) + var slotsButton = lobby.GetOrNull("SLOTS_DROPDOWNBUTTON"); + if (slotsButton != null) { - assignTeams.IsVisible = () => Game.IsHost; - assignTeams.IsDisabled = () => gameStarting || orderManager.LobbyInfo.Clients.Count(c => c.Slot != null) < 2 - || orderManager.LocalClient == null || orderManager.LocalClient.IsReady; + slotsButton.IsDisabled = () => !Game.IsHost || gameStarting || orderManager.LocalClient == null || + orderManager.LocalClient.IsReady || !orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots || !s.LockTeam); - assignTeams.OnMouseDown = _ => + var aiModes = Rules.Info["player"].Traits.WithInterface().Select(t => t.Name); + slotsButton.OnMouseDown = _ => { - var options = Enumerable.Range(1, orderManager.LobbyInfo.Clients.Count(c => c.Slot != null).Clamp(1, 8) - 1).Select(d => new DropDownOption + var options = new Dictionary>(); + + var botController = orderManager.LobbyInfo.Clients.Where(c => c.IsAdmin).FirstOrDefault(); + if (orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots)) { - Title = (d == 1 ? "All vs Host" : "{0} Teams".F(d)), - IsSelected = () => false, - OnClick = () => orderManager.IssueOrder(Order.Command("assignteams {0}".F(d.ToString()))) - }); + var botOptions = new List(){ new DropDownOption() + { + Title = "Add", + IsSelected = () => false, + OnClick = () => + { + foreach (var slot in orderManager.LobbyInfo.Slots) + { + var bot = aiModes.Random(Game.CosmeticRandom); + var c = orderManager.LobbyInfo.ClientInSlot(slot.Key); + if (slot.Value.AllowBots == true && (c == null || c.Bot != null)) + orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key, botController.Index, bot))); + } + } + }}; + + if (orderManager.LobbyInfo.Clients.Any(c => c.Bot != null)) + { + botOptions.Add(new DropDownOption() + { + Title = "Remove", + IsSelected = () => false, + OnClick = () => + { + foreach (var slot in orderManager.LobbyInfo.Slots) + { + var c = orderManager.LobbyInfo.ClientInSlot(slot.Key); + if (c != null && c.Bot != null) + orderManager.IssueOrder(Order.Command("slot_open "+slot.Value.PlayerReference)); + } + } + }); + } + + options.Add("Bots", botOptions); + } + + var teamCount = (orderManager.LobbyInfo.Slots.Count(s => !s.Value.LockTeam && orderManager.LobbyInfo.ClientInSlot(s.Key) != null) + 1) / 2; + if (teamCount >= 1) + { + var teamOptions = Enumerable.Range(0, teamCount + 1).Reverse().Select(d => new DropDownOption + { + Title = (d > 1 ? "{0} Teams".F(d) : d == 1 ? "Humans vs Bots" : "Free for all"), + IsSelected = () => false, + OnClick = () => orderManager.IssueOrder(Order.Command("assignteams {0}".F(d.ToString()))) + }); + + options.Add("Teams", teamOptions); + } + Func setupItem = (option, template) => { var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick); item.Get("LABEL").GetText = () => option.Title; return item; }; - assignTeams.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", options.Count() * 30, options, setupItem); + slotsButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 175, options, setupItem); }; } var disconnectButton = lobby.Get("DISCONNECT_BUTTON"); disconnectButton.OnClick = () => { CloseWindow(); onExit(); }; - var addBotsButton = lobby.Get("ADD_BOTS"); - addBotsButton.IsVisible = () => Game.IsHost; - addBotsButton.IsDisabled = () => !Game.IsHost || gameStarting || orderManager.LocalClient == null - || orderManager.LocalClient.IsReady || !orderManager.LobbyInfo.Slots.Values.Any(s => s.AllowBots); - addBotsButton.OnClick = () => { - var aiModes = Rules.Info["player"].Traits.WithInterface().Select(t => t.Name); - foreach (var slot in orderManager.LobbyInfo.Slots) - { - var bot = aiModes.Random(Game.CosmeticRandom); - var c = orderManager.LobbyInfo.ClientInSlot(slot.Key); - if (slot.Value.AllowBots == true && (c == null || c.Bot != null)) - orderManager.IssueOrder(Order.Command("slot_bot {0} {1} {2}".F(slot.Key,0,bot))); - } - }; - var allowCheats = lobby.Get("ALLOWCHEATS_CHECKBOX"); allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats; allowCheats.IsDisabled = () => !Game.IsHost || gameStarting || orderManager.LocalClient == null diff --git a/mods/cnc/chrome/lobby.yaml b/mods/cnc/chrome/lobby.yaml index 6b2c34534d..dee972f74b 100644 --- a/mods/cnc/chrome/lobby.yaml +++ b/mods/cnc/chrome/lobby.yaml @@ -94,28 +94,25 @@ Container@SERVER_LOBBY: Y:257 Width:130 Height:20 - Text: Debug Menu + Text:Cheats Checkbox@CRATES_CHECKBOX: - X:160 + X:120 Y:257 Width:80 Height:20 - Text: Crates - Button@ADD_BOTS: - X:398-120-10 + Text:Crates + DropDownButton@SLOTS_DROPDOWNBUTTON: + X:213 Y:255 - Width:120 + Width:150 Height:25 - Text:Add Bots - Font:Bold - DropDownButton@ASSIGNTEAMS_DROPDOWNBUTTON: - X:398 + Text:Slot Options + Button@CHANGEMAP_BUTTON: + X:368 Y:255 - Width:120 + Width:150 Height:25 - Font:Bold - Visible:false - Text:Assign + Text:Change Map ScrollPanel@CHAT_DISPLAY: X:15 Y:285 @@ -170,12 +167,6 @@ Container@SERVER_LOBBY: Width:140 Height:35 Text:Music - Button@CHANGEMAP_BUTTON: - X:450 - Y:499 - Width:140 - Height:35 - Text:Change Map Button@START_GAME_BUTTON: X:600 Y:499 diff --git a/mods/ra/chrome/lobby.yaml b/mods/ra/chrome/lobby.yaml index d5701507ce..29210a6f0e 100644 --- a/mods/ra/chrome/lobby.yaml +++ b/mods/ra/chrome/lobby.yaml @@ -125,21 +125,13 @@ Background@SERVER_LOBBY: Height:25 Text:Change Map Font:Bold - Button@ADD_BOTS: - X:PARENT_RIGHT-154 - Y:PARENT_BOTTOM-(289-25-5) - Width:120 - Height:25 - Text:Add Bots - Font:Bold - DropDownButton@ASSIGNTEAMS_DROPDOWNBUTTON: + DropDownButton@SLOTS_DROPDOWNBUTTON: X:PARENT_RIGHT-154 Y:PARENT_BOTTOM-229 Width:120 Height:25 Font:Bold - Visible:false - Text:Assign + Text:Admin DropDownButton@DIFFICULTY_DROPDOWNBUTTON: X:PARENT_RIGHT-154 Y:PARENT_BOTTOM-199