diff --git a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
index 61f99472d9..5d88daefe5 100644
--- a/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
+++ b/OpenRA.Mods.Cnc/OpenRA.Mods.Cnc.csproj
@@ -73,6 +73,7 @@
+
diff --git a/OpenRA.Mods.Cnc/Widgets/CncLobbyLogic.cs b/OpenRA.Mods.Cnc/Widgets/CncLobbyLogic.cs
new file mode 100755
index 0000000000..abeaff5e40
--- /dev/null
+++ b/OpenRA.Mods.Cnc/Widgets/CncLobbyLogic.cs
@@ -0,0 +1,480 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
+ * This file is part of OpenRA, which is free software. It is made
+ * available to you under the terms of the GNU General Public License
+ * as published by the Free Software Foundation. For more information,
+ * see COPYING.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using OpenRA.FileFormats;
+using OpenRA.Network;
+using OpenRA.Traits;
+using OpenRA.Widgets;
+using OpenRA.Graphics;
+
+namespace OpenRA.Mods.Cnc.Widgets
+{
+ public class CncLobbyLogic : IWidgetDelegate
+ {
+ Widget LocalPlayerTemplate, RemotePlayerTemplate, EmptySlotTemplate, EmptySlotTemplateHost;
+ ScrollPanelWidget Players;
+ Dictionary CountryNames;
+ string MapUid;
+ Map Map;
+
+ public static ColorRamp CurrentColorPreview;
+
+ readonly OrderManager orderManager;
+ readonly WorldRenderer worldRenderer;
+ [ObjectCreator.UseCtor]
+ internal CncLobbyLogic([ObjectCreator.Param( "widget" )] Widget lobby,
+ [ObjectCreator.Param] OrderManager orderManager,
+ [ObjectCreator.Param] WorldRenderer worldRenderer)
+ {
+ this.orderManager = orderManager;
+ this.worldRenderer = worldRenderer;
+
+ Game.LobbyInfoChanged += UpdateCurrentMap;
+ UpdateCurrentMap();
+
+ CurrentColorPreview = Game.Settings.Player.ColorRamp;
+
+ Players = lobby.GetWidget("PLAYERS");
+ LocalPlayerTemplate = Players.GetWidget("TEMPLATE_LOCAL");
+ RemotePlayerTemplate = Players.GetWidget("TEMPLATE_REMOTE");
+ EmptySlotTemplate = Players.GetWidget("TEMPLATE_EMPTY");
+ EmptySlotTemplateHost = Players.GetWidget("TEMPLATE_EMPTY_HOST");
+
+ var mapPreview = lobby.GetWidget("MAP_PREVIEW");
+ mapPreview.Map = () => Map;
+ mapPreview.OnMouseDown = mi =>
+ {
+ var map = mapPreview.Map();
+ if (map == null || mi.Button != MouseButton.Left
+ || orderManager.LocalClient.State == Session.ClientState.Ready)
+ return false;
+
+ var p = map.SpawnPoints
+ .Select((sp, i) => Pair.New(mapPreview.ConvertToPreview(map, sp), i))
+ .Where(a => (a.First - mi.Location).LengthSquared < 64)
+ .Select(a => a.Second + 1)
+ .FirstOrDefault();
+
+ var owned = orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == p);
+ if (p == 0 || !owned)
+ orderManager.IssueOrder(Order.Command("spawn {0}".F(p)));
+
+ return true;
+ };
+
+ mapPreview.SpawnColors = () =>
+ {
+ var spawns = Map.SpawnPoints;
+ var sc = new Dictionary();
+
+ for (int i = 1; i <= spawns.Count(); i++)
+ {
+ var client = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.SpawnPoint == i);
+ if (client == null)
+ continue;
+ sc.Add(spawns.ElementAt(i - 1), client.ColorRamp.GetColor(0));
+ }
+ return sc;
+ };
+
+ CountryNames = Rules.Info["world"].Traits.WithInterface().ToDictionary(a => a.Race, a => a.Name);
+ CountryNames.Add("random", "Random");
+
+ var mapButton = lobby.GetWidget("CHANGEMAP_BUTTON");
+ mapButton.OnMouseUp = mi =>
+ {
+ Widget.OpenWindow( "MAP_CHOOSER", new Dictionary { { "orderManager", orderManager }, { "mapName", MapUid } } );
+ return true;
+ };
+
+ mapButton.IsVisible = () => mapButton.Visible && Game.IsHost;
+
+ var disconnectButton = lobby.GetWidget("DISCONNECT_BUTTON");
+ disconnectButton.OnMouseUp = mi =>
+ {
+ Game.Disconnect();
+ Widget.CloseWindow();
+ Widget.LoadWidget("MENU_BACKGROUND");
+ return true;
+ };
+
+ var lockTeamsCheckbox = lobby.GetWidget("LOCKTEAMS_CHECKBOX");
+ lockTeamsCheckbox.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.LockTeams;
+ lockTeamsCheckbox.OnChange += _ =>
+ {
+ if (Game.IsHost)
+ orderManager.IssueOrder(Order.Command(
+ "lockteams {0}".F(!orderManager.LobbyInfo.GlobalSettings.LockTeams)));
+ };
+
+ var allowCheats = lobby.GetWidget("ALLOWCHEATS_CHECKBOX");
+ allowCheats.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowCheats;
+ allowCheats.OnChange += _ =>
+ {
+ if (Game.IsHost)
+ orderManager.IssueOrder(Order.Command(
+ "allowcheats {0}".F(!orderManager.LobbyInfo.GlobalSettings.AllowCheats)));
+ };
+
+ var startGameButton = lobby.GetWidget("START_GAME_BUTTON");
+ startGameButton.OnMouseUp = mi =>
+ {
+ mapButton.Visible = false;
+ disconnectButton.Visible = false;
+ lockTeamsCheckbox.Visible = false;
+ orderManager.IssueOrder(Order.Command("startgame"));
+ return true;
+ };
+
+ // Todo: Only show if the map requirements are met for player slots
+ startGameButton.IsVisible = () => Game.IsHost;
+ Game.LobbyInfoChanged += UpdatePlayerList;
+
+ Game.AddChatLine += lobby.GetWidget("CHAT_DISPLAY").AddLine;
+
+ bool teamChat = false;
+ var chatLabel = lobby.GetWidget("LABEL_CHATTYPE");
+ var chatTextField = lobby.GetWidget("CHAT_TEXTFIELD");
+ chatTextField.OnEnterKey = () =>
+ {
+ if (chatTextField.Text.Length == 0)
+ return true;
+
+ var order = (teamChat) ? Order.TeamChat(chatTextField.Text) : Order.Chat(chatTextField.Text);
+ orderManager.IssueOrder(order);
+ chatTextField.Text = "";
+ return true;
+ };
+
+ chatTextField.OnTabKey = () =>
+ {
+ teamChat ^= true;
+ chatLabel.Text = (teamChat) ? "Team:" : "Chat:";
+ return true;
+ };
+ }
+
+ void UpdatePlayerColor(float hf, float sf, float lf, float r)
+ {
+ var ramp = new ColorRamp((byte) (hf*255), (byte) (sf*255), (byte) (lf*255), (byte)(r*255));
+ Game.Settings.Player.ColorRamp = ramp;
+ Game.Settings.Save();
+ orderManager.IssueOrder(Order.Command("color {0}".F(ramp)));
+ }
+
+ void UpdateColorPreview(float hf, float sf, float lf, float r)
+ {
+ CurrentColorPreview = new ColorRamp((byte)(hf * 255), (byte)(sf * 255), (byte)(lf * 255), (byte)(r * 255));
+ }
+
+ void UpdateCurrentMap()
+ {
+ if (MapUid == orderManager.LobbyInfo.GlobalSettings.Map) return;
+ MapUid = orderManager.LobbyInfo.GlobalSettings.Map;
+ Map = new Map(Game.modData.AvailableMaps[MapUid].Path);
+
+ var title = Widget.RootWidget.GetWidget("TITLE");
+ title.Text = orderManager.LobbyInfo.GlobalSettings.ServerName;
+ }
+
+ Session.Client GetClientInSlot(Session.Slot slot)
+ {
+ return orderManager.LobbyInfo.ClientInSlot( slot );
+ }
+
+ bool ShowSlotDropDown(Session.Slot slot, ButtonWidget name, bool showBotOptions)
+ {
+ var dropDownOptions = new List>
+ {
+ new Pair( "Open",
+ () => orderManager.IssueOrder( Order.Command( "slot_open " + slot.Index ) )),
+ new Pair( "Closed",
+ () => orderManager.IssueOrder( Order.Command( "slot_close " + slot.Index ) )),
+ };
+
+ if (showBotOptions)
+ {
+ var bots = Rules.Info["player"].Traits.WithInterface().Select(t => t.Name);
+ bots.Do(bot =>
+ dropDownOptions.Add(new Pair("Bot: {0}".F(bot),
+ () => orderManager.IssueOrder(Order.Command("slot_bot {0} {1}".F(slot.Index, bot))))));
+ }
+
+ DropDownButtonWidget.ShowDropDown( name,
+ dropDownOptions,
+ (ac, w) => new LabelWidget
+ {
+ Bounds = new Rectangle(0, 0, w, 24),
+ Text = " {0}".F(ac.First),
+ OnMouseUp = mi => { ac.Second(); return true; },
+ });
+ return true;
+ }
+
+ bool ShowRaceDropDown(Session.Slot s, ButtonWidget race)
+ {
+ if (Map.Players[s.MapPlayer].LockRace)
+ return false;
+
+ var dropDownOptions = new List>();
+ foreach (var c in CountryNames)
+ {
+ var cc = c;
+ dropDownOptions.Add(new Pair( cc.Key,
+ () => orderManager.IssueOrder( Order.Command("race "+cc.Key) )) );
+ };
+
+ DropDownButtonWidget.ShowDropDown( race,
+ dropDownOptions,
+ (ac, w) =>
+ {
+ var ret = new LabelWidget
+ {
+ Bounds = new Rectangle(0, 0, w, 24),
+ Text = " {0}".F(CountryNames[ac.First]),
+ OnMouseUp = mi => { ac.Second(); return true; },
+ };
+
+ ret.AddChild(new ImageWidget
+ {
+ Bounds = new Rectangle(5, 5, 40, 15),
+ GetImageName = () => ac.First,
+ GetImageCollection = () => "flags",
+ });
+ return ret;
+ });
+ return true;
+ }
+
+ bool ShowTeamDropDown(ButtonWidget team)
+ {
+ var dropDownOptions = new List>();
+ for (int i = 0; i <= Map.PlayerCount; i++)
+ {
+ var ii = i;
+ dropDownOptions.Add(new Pair( ii == 0 ? "-" : ii.ToString(),
+ () => orderManager.IssueOrder( Order.Command("team "+ii) )) );
+ };
+
+ DropDownButtonWidget.ShowDropDown( team,
+ dropDownOptions,
+ (ac, w) => new LabelWidget
+ {
+ Bounds = new Rectangle(0, 0, w, 24),
+ Text = " {0}".F(ac.First),
+ OnMouseUp = mi => { ac.Second(); return true; },
+ });
+ return true;
+ }
+
+ bool ShowColorDropDown(Session.Slot s, ButtonWidget color)
+ {
+ if (Map.Players[s.MapPlayer].LockColor)
+ return false;
+
+ var colorChooser = Game.modData.WidgetLoader.LoadWidget( new Dictionary() { {"worldRenderer", worldRenderer} }, null, "COLOR_CHOOSER" );
+ var hueSlider = colorChooser.GetWidget("HUE_SLIDER");
+ hueSlider.SetOffset(orderManager.LocalClient.ColorRamp.H / 255f);
+
+ var satSlider = colorChooser.GetWidget("SAT_SLIDER");
+ satSlider.SetOffset(orderManager.LocalClient.ColorRamp.S / 255f);
+
+ var lumSlider = colorChooser.GetWidget("LUM_SLIDER");
+ lumSlider.SetOffset(orderManager.LocalClient.ColorRamp.L / 255f);
+
+ var rangeSlider = colorChooser.GetWidget("RANGE_SLIDER");
+ rangeSlider.SetOffset(orderManager.LocalClient.ColorRamp.R / 255f);
+
+ hueSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+ satSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+ lumSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+ rangeSlider.OnChange += _ => UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+ UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+
+ DropDownButtonWidget.ShowDropPanel(color, colorChooser, new List() {colorChooser.GetWidget("BUTTON_OK")}, () => {
+ UpdateColorPreview(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+ UpdatePlayerColor(hueSlider.GetOffset(), satSlider.GetOffset(), lumSlider.GetOffset(), rangeSlider.GetOffset());
+ return true;
+ });
+ return true;
+ }
+
+ void UpdatePlayerList()
+ {
+ // This causes problems for people who are in the process of editing their names (the widgets vanish from beneath them)
+ // Todo: handle this nicer
+ Players.RemoveChildren();
+
+ foreach (var slot in orderManager.LobbyInfo.Slots)
+ {
+ var s = slot;
+ var c = GetClientInSlot(s);
+ Widget template;
+
+ if (c == null)
+ {
+ if (Game.IsHost)
+ {
+ if (slot.Spectator)
+ {
+ template = EmptySlotTemplateHost.Clone();
+ var name = template.GetWidget("NAME");
+ name.GetText = () => s.Closed ? "Closed" : "Open";
+ name.OnMouseDown = _ => ShowSlotDropDown(s, name, false);
+ var btn = template.GetWidget("JOIN");
+ btn.GetText = () => "Spectate in this slot";
+ }
+ else
+ {
+ template = EmptySlotTemplateHost.Clone();
+ var name = template.GetWidget("NAME");
+ name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
+ name.OnMouseDown = _ => ShowSlotDropDown(s, name, Map.Players[ s.MapPlayer ].AllowBots);
+ }
+ }
+ else
+ {
+ template = EmptySlotTemplate.Clone();
+ var name = template.GetWidget("NAME");
+ name.GetText = () => s.Closed ? "Closed" : (s.Bot == null) ? "Open" : s.Bot;
+
+ if (slot.Spectator)
+ {
+ var btn = template.GetWidget("JOIN");
+ btn.GetText = () => "Spectate in this slot";
+ }
+ }
+
+ var join = template.GetWidget("JOIN");
+ if (join != null)
+ {
+ join.OnMouseUp = _ => { orderManager.IssueOrder(Order.Command("slot " + s.Index)); return true; };
+ join.IsVisible = () => !s.Closed && s.Bot == null && orderManager.LocalClient.State != Session.ClientState.Ready;
+ }
+
+ var bot = template.GetWidget("BOT");
+ if (bot != null)
+ bot.IsVisible = () => s.Bot != null;
+ }
+ else if (c.Index == orderManager.LocalClient.Index && c.State != Session.ClientState.Ready)
+ {
+ template = LocalPlayerTemplate.Clone();
+ var name = template.GetWidget("NAME");
+ name.Text = c.Name;
+ name.OnEnterKey = () =>
+ {
+ name.Text = name.Text.Trim();
+ if (name.Text.Length == 0)
+ name.Text = c.Name;
+
+ name.LoseFocus();
+ if (name.Text == c.Name)
+ return true;
+
+ orderManager.IssueOrder(Order.Command("name " + name.Text));
+ Game.Settings.Player.Name = name.Text;
+ Game.Settings.Save();
+ return true;
+ };
+ name.OnLoseFocus = () => name.OnEnterKey();
+
+ var color = template.GetWidget("COLOR");
+ color.OnMouseUp = _ => ShowColorDropDown(s, color);
+
+ var colorBlock = color.GetWidget("COLORBLOCK");
+ colorBlock.GetColor = () => c.ColorRamp.GetColor(0);
+
+ var faction = template.GetWidget("FACTION");
+ faction.OnMouseDown = _ => ShowRaceDropDown(s, faction);
+
+ var factionname = faction.GetWidget("FACTIONNAME");
+ factionname.GetText = () => CountryNames[c.Country];
+ var factionflag = faction.GetWidget("FACTIONFLAG");
+ factionflag.GetImageName = () => c.Country;
+ factionflag.GetImageCollection = () => "flags";
+
+ var team = template.GetWidget("TEAM");
+ team.OnMouseDown = _ => ShowTeamDropDown(team);
+ team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
+
+ var status = template.GetWidget("STATUS");
+ status.IsChecked = () => c.State == Session.ClientState.Ready;
+ status.OnChange += CycleReady;
+
+ var spectator = template.GetWidget("SPECTATOR");
+
+ Session.Slot slot1 = slot;
+ color.IsVisible = () => !slot1.Spectator;
+ colorBlock.IsVisible = () => !slot1.Spectator;
+ faction.IsVisible = () => !slot1.Spectator;
+ factionname.IsVisible = () => !slot1.Spectator;
+ factionflag.IsVisible = () => !slot1.Spectator;
+ team.IsVisible = () => !slot1.Spectator;
+ spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null;
+ }
+ else
+ {
+ template = RemotePlayerTemplate.Clone();
+ template.GetWidget("NAME").GetText = () => c.Name;
+ var color = template.GetWidget("COLOR");
+ color.GetColor = () => c.ColorRamp.GetColor(0);
+
+ var faction = template.GetWidget("FACTION");
+ var factionname = faction.GetWidget("FACTIONNAME");
+ factionname.GetText = () => CountryNames[c.Country];
+ var factionflag = faction.GetWidget("FACTIONFLAG");
+ factionflag.GetImageName = () => c.Country;
+ factionflag.GetImageCollection = () => "flags";
+
+ var team = template.GetWidget("TEAM");
+ team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString();
+
+ var status = template.GetWidget("STATUS");
+ status.IsChecked = () => c.State == Session.ClientState.Ready;
+ if (c.Index == orderManager.LocalClient.Index)
+ status.OnChange += CycleReady;
+
+ var spectator = template.GetWidget("SPECTATOR");
+
+ Session.Slot slot1 = slot;
+ color.IsVisible = () => !slot1.Spectator;
+ faction.IsVisible = () => !slot1.Spectator;
+ factionname.IsVisible = () => !slot1.Spectator;
+ factionflag.IsVisible = () => !slot1.Spectator;
+ team.IsVisible = () => !slot1.Spectator;
+ spectator.IsVisible = () => slot1.Spectator || slot1.Bot != null;
+
+ var kickButton = template.GetWidget("KICK");
+ kickButton.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index;
+ kickButton.OnMouseUp = mi =>
+ {
+ orderManager.IssueOrder(Order.Command("kick " + c.Slot));
+ return true;
+ };
+ }
+
+ template.Id = "SLOT_{0}".F(s.Index);
+ template.IsVisible = () => true;
+ Players.AddChild(template);
+ }
+ }
+
+ bool SpawnPointAvailable(int index) { return (index == 0) || orderManager.LobbyInfo.Clients.All(c => c.SpawnPoint != index); }
+
+ void CycleReady(bool ready)
+ {
+ orderManager.IssueOrder(Order.Command("ready"));
+ }
+ }
+}
diff --git a/mods/cnc/chrome/lobby.yaml b/mods/cnc/chrome/lobby.yaml
new file mode 100644
index 0000000000..d16b9034ac
--- /dev/null
+++ b/mods/cnc/chrome/lobby.yaml
@@ -0,0 +1,430 @@
+Container@SERVER_LOBBY:
+ Id:SERVER_LOBBY
+ Delegate:CncLobbyLogic
+ X:(WINDOW_RIGHT - WIDTH)/2
+ Y:(WINDOW_BOTTOM - 500)/2
+ Width:740
+ Height:535
+ Children:
+ Label@TITLE:
+ Id:TITLE
+ Width:740
+ Y:0-25
+ Font:BigBold
+ Contrast:true
+ Align:Center
+ Background@bg:
+ Width:740
+ Height:500
+ Background:panel-black
+ Children:
+ Background@MAP_BG:
+ X:PARENT_RIGHT-15-WIDTH
+ Y:30
+ Width:194
+ Height:194
+ Background:panel-darkred
+ Children:
+ MapPreview@MAP_PREVIEW:
+ Id:MAP_PREVIEW
+ X:1
+ Y:1
+ Width:192
+ Height:192
+ Checkbox@LOCKTEAMS_CHECKBOX:
+ Id:LOCKTEAMS_CHECKBOX
+ X:PARENT_RIGHT-209
+ Y:230
+ Width:80
+ Height:20
+ Text: Lock Teams
+ Checkbox@ALLOWCHEATS_CHECKBOX:
+ Id:ALLOWCHEATS_CHECKBOX
+ X:PARENT_RIGHT-209
+ Y:255
+ Width:80
+ Height:20
+ Text: Allow Cheats
+ ScrollPanel@PLAYERS:
+ Id:PLAYERS
+ X:15
+ Y:30
+ Width:504
+ ItemSpacing:5
+ Height:245
+ Children:
+ Container@TEMPLATE_LOCAL:
+ Id:TEMPLATE_LOCAL
+ X:5
+ Y:0
+ Width:475
+ Height:25
+ Visible:false
+ Children:
+ TextField@NAME:
+ Id:NAME
+ Text:Name
+ Width:150
+ Height:25
+ X:0
+ Y:0
+ MaxLength:16
+ DropDownButton@COLOR:
+ Id:COLOR
+ Width:80
+ Height:25
+ X:160
+ Y:0
+ Children:
+ ColorBlock@COLORBLOCK:
+ Id:COLORBLOCK
+ X:5
+ Y:6
+ Width:PARENT_RIGHT-35
+ Height:PARENT_BOTTOM-12
+ DropDownButton@FACTION:
+ Id:FACTION
+ Width:130
+ Height:25
+ X:250
+ Y:0
+ Children:
+ Image@FACTIONFLAG:
+ Id:FACTIONFLAG
+ Width:30
+ Height:15
+ X:5
+ Y:5
+ Label@FACTIONNAME:
+ Id:FACTIONNAME
+ Text:Faction
+ Width:60
+ Height:25
+ X:40
+ Y:0
+ DropDownButton@TEAM:
+ Id:TEAM
+ Text:Team
+ Width:48
+ Height:25
+ X:390
+ Y:0
+ Checkbox@STATUS:
+ Id:STATUS
+ X:448
+ Y:2
+ Width:20
+ Height:20
+ Label@SPECTATOR:
+ Id:SPECTATOR
+ Text:Spectator
+ Width:278
+ Height:25
+ X:160
+ Y:0
+ Align:Center
+ Bold:True
+ Container@TEMPLATE_REMOTE:
+ Id:TEMPLATE_REMOTE
+ X:5
+ Y:0
+ Width:475
+ Height:25
+ Visible:false
+ Children:
+ Label@NAME:
+ Id:NAME
+ Text:Name
+ Width:145
+ Height:25
+ X:5
+ Y:0-1
+ Button@KICK:
+ Id:KICK
+ Text:X
+ Width:25
+ Height:23
+ X:125
+ Y:2
+ Bold:Yes
+ ColorBlock@COLOR:
+ Id:COLOR
+ X:165
+ Y:6
+ Width:45
+ Height:13
+ Label@FACTION:
+ Id:FACTION
+ Width:130
+ Height:25
+ X:250
+ Y:0
+ Children:
+ Image@FACTIONFLAG:
+ Id:FACTIONFLAG
+ Width:30
+ Height:15
+ X:5
+ Y:5
+ Label@FACTIONNAME:
+ Id:FACTIONNAME
+ Text:Faction
+ Width:60
+ Height:25
+ X:40
+ Y:0
+ Label@TEAM:
+ Id:TEAM
+ Text:Team
+ Width:23
+ Height:25
+ Align:Center
+ X:390
+ Y:0
+ Checkbox@STATUS:
+ Id:STATUS
+ X:448
+ Y:2
+ Width:20
+ Height:20
+ Label@SPECTATOR:
+ Id:SPECTATOR
+ Text:Spectator
+ Width:278
+ Height:25
+ X:160
+ Y:0
+ Align:Center
+ Bold:True
+ Container@TEMPLATE_EMPTY:
+ Id:TEMPLATE_EMPTY
+ X:5
+ Y:0
+ Width:475
+ Height:25
+ Visible:false
+ Children:
+ Label@NAME:
+ Id:NAME
+ Text:Name
+ Width:145
+ Height:25
+ X:5
+ Y:0-1
+ Button@JOIN:
+ Id:JOIN
+ Text:Play in this slot
+ Width:278
+ Height:25
+ X:160
+ Y:0
+ Label@BOT:
+ Id:BOT
+ Text:Bot
+ Width:278
+ Height:25
+ X:160
+ Y:0
+ Align:Center
+ Bold:True
+ Container@TEMPLATE_EMPTY_HOST:
+ Id:TEMPLATE_EMPTY_HOST
+ X:5
+ Y:0
+ Width:400
+ Height:25
+ Visible:false
+ Children:
+ DropDownButton@NAME:
+ Id:NAME
+ Text:Name
+ Width:150
+ Height:25
+ X:0
+ Y:0
+ Button@JOIN:
+ Id:JOIN
+ Text:Play in this slot
+ Width:278
+ Height:25
+ X:160
+ Y:0
+ Label@BOT:
+ Id:BOT
+ Text:Bot
+ Width:278
+ Height:25
+ X:160
+ Y:0
+ Align:Center
+ Bold:True
+ Container@LABEL_CONTAINER:
+ X:25
+ Y:5
+ Children:
+ Label@LABEL_LOBBY_NAME:
+ Id:LABEL_LOBBY_NAME
+ Width:150
+ Height:25
+ X:0
+ Y:0
+ Text:Name
+ Align:Center
+ Bold:True
+ Label@LABEL_LOBBY_COLOR:
+ Id:LABEL_LOBBY_COLOR
+ Width:80
+ Height:25
+ X:160
+ Y:0
+ Text:Color
+ Align:Center
+ Bold:True
+ Label@LABEL_LOBBY_FACTION:
+ Id:LABEL_LOBBY_FACTION
+ Width:130
+ Height:25
+ X:250
+ Y:0
+ Text:Faction
+ Align:Center
+ Bold:True
+ Label@LABEL_LOBBY_TEAM:
+ Id:LABEL_LOBBY_TEAM
+ Width:48
+ Height:25
+ X:390
+ Y:0
+ Text:Team
+ Align:Center
+ Bold:True
+ Label@LABEL_LOBBY_STATUS:
+ Id:LABEL_LOBBY_STATUS
+ X:448
+ Y:0
+ Width:20
+ Height:25
+ Text:Ready
+ Align:Left
+ Bold:True
+ ChatDisplay@CHAT_DISPLAY:
+ Id:CHAT_DISPLAY
+ X:15
+ Y:285
+ Width:PARENT_RIGHT - 30
+ Height:PARENT_BOTTOM - 55 - 275
+ Notification: beepy2.aud
+ TextField@CHAT_TEXTFIELD:
+ Id:CHAT_TEXTFIELD
+ X:15
+ Y:PARENT_BOTTOM - 15 - HEIGHT
+ LeftMargin:50
+ Width:PARENT_RIGHT - 30
+ Height:25
+ Children:
+ Label@LABEL_CHATTYPE:
+ Id:LABEL_CHATTYPE
+ Y:0-1
+ Width:45
+ Height:25
+ Align:Right
+ Text:Chat:
+ CncMenuButton@START_GAME_BUTTON:
+ Id:START_GAME_BUTTON
+ X:0
+ Y:499
+ Width:140
+ Height:35
+ Text:Start Game
+ CncMenuButton@CHANGEMAP_BUTTON:
+ Id:CHANGEMAP_BUTTON
+ X:150
+ Y:499
+ Width:140
+ Height:35
+ Text:Change Map
+ CncMenuButton@DISCONNECT_BUTTON:
+ Id:DISCONNECT_BUTTON
+ X:600
+ Y:499
+ Width:140
+ Height:35
+ Text:Leave Game
+Background@COLOR_CHOOSER:
+ Id:COLOR_CHOOSER
+ Background:dialog2
+ Width:310
+ Height:120
+ Children:
+ Button@BUTTON_OK:
+ Id:BUTTON_OK
+ X:210
+ Y:85
+ Width:90
+ Height:25
+ Text:Ok
+ Bold:True
+ ShpImage@FACT:
+ Id:FACT
+ X:220
+ Y:10
+ Image:fact
+ Palette:colorpicker
+ Label@HUE_LABEL:
+ X:0
+ Y:5
+ Width:40
+ Height:20
+ Align: Right
+ Text: Hue:
+ Slider@HUE:
+ Id:HUE_SLIDER
+ X:43
+ Y:10
+ Width:160
+ Height:20
+ Ticks:5
+ Label@SAT_LABEL:
+ X:0
+ Y:30
+ Width:40
+ Height:20
+ Align: Right
+ Text: Sat:
+ Slider@SAT:
+ Id:SAT_SLIDER
+ X:43
+ Y:35
+ Width:160
+ Height:20
+ Ticks:5
+ Label@LUM_LABEL:
+ X:0
+ Y:55
+ Width:40
+ Height:20
+ Align: Right
+ Text: Lum:
+ Slider@LUM:
+ Id:LUM_SLIDER
+ X:43
+ Y:60
+ Width:160
+ Height:20
+ Ticks:5
+ Range:0.2,1
+ Label@RANGE_LABEL:
+ X:0
+ Y:80
+ Width:40
+ Height:20
+ Align: Right
+ Text: Ran:
+ Slider@RANGE:
+ Id:RANGE_SLIDER
+ X:43
+ Y:85
+ Width:160
+ Height:20
+ Ticks:5
+ Range:0,0.25
diff --git a/mods/cnc/chrome/unused/mapchooser.yaml b/mods/cnc/chrome/unused/mapchooser.yaml
new file mode 100644
index 0000000000..bcdac87c23
--- /dev/null
+++ b/mods/cnc/chrome/unused/mapchooser.yaml
@@ -0,0 +1,214 @@
+Background@MAP_CHOOSER:
+ Id:MAP_CHOOSER
+ X:(WINDOW_RIGHT - WIDTH)/2
+ Y:(WINDOW_BOTTOM - HEIGHT)/2
+ Delegate:MapChooserDelegate
+ Width:800
+ Height:600
+ Children:
+ Label@MAPCHOOSER_TITLE:
+ X:0
+ Y:17
+ Align:Center
+ Width:800
+ Height:20
+ Text:Choose Map
+ Bold:True
+ ScrollPanel@MAP_LIST:
+ Id:MAP_LIST
+ X:20
+ Y:67
+ Width:504
+ Height:474
+ Children:
+ Container@MAP_TEMPLATE:
+ Id:MAP_TEMPLATE
+ Width:PARENT_RIGHT-28
+ Height:25
+ X:2
+ Y:0
+ Visible:false
+ Children:
+ Label@TITLE:
+ X:10
+ Id:TITLE
+ Width:PARENT_RIGHT-100
+ Height:25
+ Label@PLAYERS:
+ Id:PLAYERS
+ X:PARENT_RIGHT-150
+ Width:30
+ Height:25
+ Label@TYPE:
+ Id:TYPE
+ Width:90
+ X:PARENT_RIGHT-100
+ Align:Right
+ Height:25
+ Container@MAP_LABELS:
+ Width:494
+ Height:25
+ X:25
+ Y:40
+ Children:
+ Label@TITLE:
+ Width:125
+ Height:25
+ X:0
+ Y:0
+ Text:Title
+ Align:Center
+ Bold:True
+ Label@PLAYERS:
+ Text:Players
+ Bold:true
+ Width:50
+ X:304
+ Height:25
+ Label@TYPE:
+ Text:Type
+ Bold:true
+ Width:50
+ X:420
+ Height:25
+ Background@MAPCHOOSER_MAP_BG:
+ X:PARENT_RIGHT-268
+ Y:50
+ Width:252
+ Height:252
+ Background:dialog3
+ Children:
+ MapPreview@MAPCHOOSER_MAP_PREVIEW:
+ Id:MAPCHOOSER_MAP_PREVIEW
+ X:4
+ Y:4
+ Width:244
+ Height:244
+ Container@MAP_LABEL_CONTAINER:
+ Width:70
+ Height:200
+ X:PARENT_RIGHT - 255
+ Y:311
+ Children:
+ Label@CURMAP_TITLE_LABEL:
+ Id:CURMAP_TITLE_LABEL
+ X:0
+ Y:0
+ Align:Right
+ Width:70
+ Height:20
+ Text:Title:
+ Bold:True
+ Label@CURMAP_TITLE:
+ Id:CURMAP_TITLE
+ X:75
+ Y:0
+ Align:Left
+ Width:70
+ Height:20
+ Label@CURMAP_AUTHOR_LABEL:
+ Id:CURMAP_AUTHOR_LABEL
+ X:0
+ Y:20
+ Align:Right
+ Width:70
+ Height:20
+ Text:Author:
+ Bold:True
+ Label@CURMAP_AUTHOR:
+ Id:CURMAP_AUTHOR
+ X:75
+ Y:20
+ Align:Left
+ Width:175
+ Height:20
+ WordWrap:True
+ Label@CURMAP_SIZE_LABEL:
+ Id:CURMAP_SIZE_LABEL
+ X:0
+ Y:40
+ Align:Right
+ Width:70
+ Height:20
+ Text:Size:
+ Bold:True
+ Label@CURMAP_SIZE:
+ Id:CURMAP_SIZE
+ X:75
+ Y:40
+ Align:Left
+ Width:70
+ Height:20
+ Label@CURMAP_THEATER_LABEL:
+ Id:CURMAP_THEATER_LABEL
+ X:0
+ Y:60
+ Align:Right
+ Width:70
+ Height:20
+ Text:Theater:
+ Bold:True
+ Label@CURMAP_THEATER:
+ Id:CURMAP_THEATER
+ X:75
+ Y:60
+ Align:Left
+ Width:70
+ Height:20
+ Label@CURMAP_PLAYERS_LABEL:
+ Id:CURMAP_PLAYERS_LABEL
+ X:0
+ Y:80
+ Align:Right
+ Width:70
+ Height:20
+ Text:Players:
+ Bold:True
+ Label@CURMAP_PLAYERS:
+ Id:CURMAP_PLAYERS
+ X:75
+ Y:80
+ Align:Left
+ Width:70
+ Height:20
+ Label@CURMAP_DESC_LABEL:
+ Id:CURMAP_DESC_LABEL
+ X:0
+ Y:100
+ Align:Right
+ Width:70
+ Height:20
+ Text:Desc:
+ Bold:True
+ Label@CURMAP_DESC:
+ Id:CURMAP_DESC
+ X:75
+ Y:100
+ Align:Left
+ Width:170
+ Height:20
+ WordWrap:True
+ Button@BUTTON_OK:
+ Id:BUTTON_OK
+ X:PARENT_RIGHT - 295
+ Y:PARENT_BOTTOM - 49
+ Width:120
+ Height:25
+ Text:Ok
+ Bold:True
+ Button@BUTTON_CANCEL:
+ Id:BUTTON_CANCEL
+ X:PARENT_RIGHT-154
+ Y:PARENT_BOTTOM-49
+ Width:120
+ Height:25
+ Text:Cancel
+ Bold:True
+ Button@BUTTON_INSTALL:
+ Id:BUTTON_INSTALL
+ X:20
+ Y:PARENT_BOTTOM-49
+ Width:120
+ Height:25
+ Text:Install Map
+ Bold:True
\ No newline at end of file
diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml
index 2480782b5b..66fcab430a 100644
--- a/mods/cnc/mod.yaml
+++ b/mods/cnc/mod.yaml
@@ -63,6 +63,7 @@ ChromeLayout:
mods/cnc/chrome/mainmenu.yaml
mods/cnc/chrome/serverbrowser.yaml
mods/cnc/chrome/directconnect.yaml
+ mods/cnc/chrome/lobby.yaml
Weapons:
mods/cnc/weapons.yaml
diff --git a/mods/cnc/uibits/panel.png b/mods/cnc/uibits/panel.png
new file mode 100644
index 0000000000..4fd615cd05
Binary files /dev/null and b/mods/cnc/uibits/panel.png differ