From 1eb7c62c62c65c96f922463023f8bde47b5e952b Mon Sep 17 00:00:00 2001 From: Sascha Biedermann Date: Thu, 28 Mar 2013 18:39:26 +0100 Subject: [PATCH 1/2] closes #2874: improved ingame chat --- OpenRA.Game/Game.cs | 2 +- OpenRA.Game/Network/Session.cs | 1 + OpenRA.Game/Network/UnitOrders.cs | 1 + OpenRA.Game/Widgets/TextFieldWidget.cs | 4 + OpenRA.Game/Widgets/Widget.cs | 2 + OpenRA.Game/World.cs | 5 +- OpenRA.Mods.RA/OpenRA.Mods.RA.csproj | 1 + .../Widgets/Logic/IngameChatLogic.cs | 156 ++++++++++++++++++ .../Widgets/Logic/IngameChromeLogic.cs | 18 +- .../Logic/IngameObserverChromeLogic.cs | 21 +-- mods/cnc-classic/mod.yaml | 1 + mods/d2k/mod.yaml | 3 +- mods/ra-classic/mod.yaml | 1 + mods/ra/chrome/ingame-chat.yaml | 71 ++++++++ mods/ra/chrome/ingame.yaml | 28 ---- mods/ra/mod.yaml | 1 + 16 files changed, 255 insertions(+), 61 deletions(-) create mode 100644 OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs create mode 100644 mods/ra/chrome/ingame-chat.yaml diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 0a3c75273a..28b7d37741 100755 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -210,7 +210,7 @@ namespace OpenRA var map = modData.PrepareMap(mapUID); viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer); - orderManager.world = new World(modData.Manifest, map, orderManager) { IsShellmap = isShellmap }; + orderManager.world = new World(modData.Manifest, map, orderManager, isShellmap); worldRenderer = new WorldRenderer(orderManager.world); if (orderManager.GameStarted) return; diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs index c10ff6fe82..bee4e6c7e8 100644 --- a/OpenRA.Game/Network/Session.cs +++ b/OpenRA.Game/Network/Session.cs @@ -59,6 +59,7 @@ namespace OpenRA.Network public string Bot; // Bot type, null for real clients public bool IsAdmin; public bool IsReady { get { return State == ClientState.Ready; } } + public bool IsObeserver { get { return Slot == null; } } } public class Slot diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index c07b5d12d3..3f0a9d096c 100755 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -44,6 +44,7 @@ namespace OpenRA.Network { var player = world != null ? world.FindPlayerByClient(client) : null; var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : ""; + suffix = client.IsObeserver ? " (Spectator)" : suffix; Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString); } else diff --git a/OpenRA.Game/Widgets/TextFieldWidget.cs b/OpenRA.Game/Widgets/TextFieldWidget.cs index 497f57adf1..fcb1cf5a1b 100644 --- a/OpenRA.Game/Widgets/TextFieldWidget.cs +++ b/OpenRA.Game/Widgets/TextFieldWidget.cs @@ -31,6 +31,7 @@ namespace OpenRA.Widgets public Func OnEnterKey = () => false; public Func OnTabKey = () => false; + public Func OnEscKey = () => false; public Action OnLoseFocus = () => { }; public int CursorPosition { get; protected set; } @@ -121,6 +122,9 @@ namespace OpenRA.Widgets if (e.KeyName == "tab" && OnTabKey()) return true; + if (e.KeyName == "escape" && OnEscKey()) + return true; + if (e.KeyName == "left") { if (CursorPosition > 0) diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index d1c0df90fa..e3c06dd1f1 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -403,6 +403,8 @@ namespace OpenRA.Widgets public override string GetCursor(int2 pos) { return null; } public override Widget Clone() { return new ContainerWidget(this); } + public Func OnKeyPress = _ => false; + public override bool HandleKeyPress(KeyInput e) { return OnKeyPress(e); } } public class WidgetArgs : Dictionary diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 7dd3fbbc35..833fc29427 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -40,7 +40,7 @@ namespace OpenRA public void AddPlayer(Player p) { Players.Add(p); } public Player LocalPlayer { get; private set; } public readonly Shroud LocalShroud; - + public bool Observer { get { return LocalPlayer == null; } } public Player RenderedPlayer; public Shroud RenderedShroud { get { return RenderedPlayer != null ? RenderedPlayer.Shroud : LocalShroud; } } @@ -90,8 +90,9 @@ namespace OpenRA } } - internal World(Manifest manifest, Map map, OrderManager orderManager) + internal World(Manifest manifest, Map map, OrderManager orderManager, bool isShellmap) { + IsShellmap = isShellmap; this.orderManager = orderManager; orderGenerator_ = new UnitOrderGenerator(); Map = map; diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 4d8584b9a2..12a4d7a117 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -375,6 +375,7 @@ + diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs new file mode 100644 index 0000000000..8ef9c850cd --- /dev/null +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs @@ -0,0 +1,156 @@ +#region Copyright & License Information +/* + * Copyright 2013 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.Drawing; +using OpenRA.Widgets; +using OpenRA.Network; + +namespace OpenRA.Mods.RA.Widgets.Logic +{ + public class IngameChatLogic + { + internal World World; + internal readonly ContainerWidget ChatOverlay; + internal readonly ChatDisplayWidget ChatOverlayDisplay; + + + internal readonly ContainerWidget ChatChrome; + internal readonly ScrollPanelWidget ChatScrollPanel; + internal readonly ContainerWidget ChatTemplate; + internal readonly TextFieldWidget ChatText; + + private bool teamChat = false; + internal bool TeamChat + { + get { return World.Observer ? false : teamChat; } + set { teamChat = value; } + } + + [ObjectCreator.UseCtor] + public IngameChatLogic(Widget widget, OrderManager orderManager, World world) + { + World = world; + var chatPanel = (ContainerWidget) widget; + + + ChatOverlay = chatPanel.Get("CHAT_OVERLAY"); + ChatOverlayDisplay = ChatOverlay.Get("CHAT_DISPLAY"); + ChatOverlay.Visible = false; + + ChatChrome = chatPanel.Get("CHAT_CHROME"); + ChatChrome.Visible = true; + + var chatMode = ChatChrome.Get("CHAT_MODE"); + chatMode.GetText = () => TeamChat ? "Team" : "All"; + chatMode.OnClick = () => TeamChat = !TeamChat; + + ChatText = ChatChrome.Get("CHAT_TEXTFIELD"); + ChatText.OnTabKey = () => { TeamChat = !TeamChat; return true; }; + ChatText.OnEnterKey = () => + { + ChatText.Text = ChatText.Text.Trim(); + if (ChatText.Text != "") + orderManager.IssueOrder(Order.Chat(TeamChat, ChatText.Text)); + CloseChat(); + return true; + }; + ChatText.OnEscKey = () => {CloseChat(); return true; }; + + var chatClose = ChatChrome.Get("CHAT_CLOSE"); + chatClose.OnClick += () => CloseChat(); + + chatPanel.OnKeyPress = (e) => + { + if (e.Event == KeyInputEvent.Up) return false; + if (!IsOpen && (e.KeyName == "enter" || e.KeyName == "return") ) + { + + var shift = e.Modifiers.HasModifier(Modifiers.Shift); + var toggle = Game.Settings.Game.TeamChatToggle ; + TeamChat = (!toggle && shift) || ( toggle && (TeamChat ^ shift) ); + OpenChat(); + return true; + } + + return false; + }; + + ChatScrollPanel = ChatChrome.Get("CHAT_SCROLLPANEL"); + ChatTemplate = ChatScrollPanel.Get("CHAT_TEMPLATE"); + + Game.AddChatLine += AddChatLine; + Game.BeforeGameStart += UnregisterEvents; + + CloseChat(); + ChatOverlayDisplay.AddLine(Color.White, null, "Use RETURN key to open chat window..."); + } + + void UnregisterEvents() + { + Game.AddChatLine -= AddChatLine; + Game.BeforeGameStart -= UnregisterEvents; + } + + public void OpenChat() + { + ChatText.Text = ""; + ChatOverlay.Visible = false; + ChatChrome.Visible = true; + ChatText.TakeFocus(new MouseInput()); + } + + public void CloseChat() + { + ChatOverlay.Visible = true; + ChatChrome.Visible = false; + ChatText.LoseFocus(); + } + + public bool IsOpen { get { return ChatChrome.IsVisible(); } } + + public void AddChatLine(Color c, string from, string text) + { + + ChatOverlayDisplay.AddLine(c, from, text); + + var template = ChatTemplate.Clone(); + var nameLabel = template.Get("NAME"); + var textLabel = template.Get("TEXT"); + + var name = ""; + if (!string.IsNullOrEmpty(from)) + name = from + ":"; + var font = Game.Renderer.Fonts[nameLabel.Font]; + var nameSize = font.Measure(from); + + nameLabel.GetColor = () => c; + nameLabel.GetText = () => name; + nameLabel.Bounds.Width = nameSize.X; + textLabel.Bounds.X += nameSize.X; + textLabel.Bounds.Width -= nameSize.X; + + // Hack around our hacky wordwrap behavior: need to resize the widget to fit the text + text = WidgetUtils.WrapText(text, textLabel.Bounds.Width, font); + textLabel.GetText = () => text; + var dh = font.Measure(text).Y - textLabel.Bounds.Height; + if (dh > 0) + { + textLabel.Bounds.Height += dh; + template.Bounds.Height += dh; + } + + ChatScrollPanel.AddChild(template); + ChatScrollPanel.ScrollToBottom(); + Sound.PlayNotification(null, "Sounds", "ChatLine", null); + } + } +} + diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs index f65470eeef..01e31e05d9 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameChromeLogic.cs @@ -22,9 +22,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic [ObjectCreator.UseCtor] public IngameChromeLogic(World world) { - Game.AddChatLine += AddChatLine; - Game.BeforeGameStart += UnregisterEvents; - var r = Ui.Root; gameRoot = r.Get("INGAME_ROOT"); var optionsBG = gameRoot.Get("INGAME_OPTIONS_BG"); @@ -58,8 +55,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic moneybin.Get("POWER_DOWN").GetKey = _ => Game.Settings.Keys.PowerDownKey; moneybin.Get("REPAIR").GetKey = _ => Game.Settings.Keys.RepairKey; - optionsBG.Get("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world); + var chatPanel = Game.LoadWidget(world, "CHAT_PANEL", Ui.Root, new WidgetArgs()); + gameRoot.AddChild(chatPanel); + optionsBG.Get("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world); optionsBG.Get("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU"); optionsBG.Get("MUSIC").OnClick = () => Ui.OpenWindow("MUSIC_MENU"); optionsBG.Get("RESUME").OnClick = () => @@ -110,16 +109,5 @@ namespace OpenRA.Mods.RA.Widgets.Logic Ui.CloseWindow(); Ui.OpenWindow("MAINMENU_BG"); } - - void UnregisterEvents() - { - Game.AddChatLine -= AddChatLine; - Game.BeforeGameStart -= UnregisterEvents; - } - - void AddChatLine(Color c, string from, string text) - { - gameRoot.Get("CHAT_DISPLAY").AddLine(c, from, text); - } } } diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameObserverChromeLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameObserverChromeLogic.cs index 9b0863d7f0..047f2411b3 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameObserverChromeLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameObserverChromeLogic.cs @@ -10,6 +10,7 @@ using OpenRA.Traits; using OpenRA.Widgets; +using OpenRA.Network; using System; using System.Drawing; using System.Linq; @@ -24,9 +25,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic [ObjectCreator.UseCtor] public IngameObserverChromeLogic(World world) { - Game.AddChatLine += AddChatLine; - Game.BeforeGameStart += UnregisterEvents; - var r = Ui.Root; gameRoot = r.Get("OBSERVER_ROOT"); var optionsBG = gameRoot.Get("INGAME_OPTIONS_BG"); @@ -59,6 +57,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic Ui.Root.Get("INGAME_STATS_BUTTON").OnClick = () => gameRoot.Get("OBSERVER_STATS").Visible ^= true; + if (!world.IsShellmap) + { + var chatPanel = Game.LoadWidget(world, "CHAT_PANEL", Ui.Root, new WidgetArgs()); + gameRoot.AddChild(chatPanel); + } + var shroudSelector = Ui.Root.GetOrNull("SHROUD_SELECTOR"); if (shroudSelector != null) { @@ -91,17 +95,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic } } - void UnregisterEvents() - { - Game.AddChatLine -= AddChatLine; - Game.BeforeGameStart -= UnregisterEvents; - } - - void AddChatLine(Color c, string from, string text) - { - gameRoot.Get("CHAT_DISPLAY").AddLine(c, from, text); - } - class DropDownOption { public string Title; diff --git a/mods/cnc-classic/mod.yaml b/mods/cnc-classic/mod.yaml index 429a605521..4bc2c14963 100644 --- a/mods/cnc-classic/mod.yaml +++ b/mods/cnc-classic/mod.yaml @@ -65,6 +65,7 @@ Assemblies: ChromeLayout: mods/ra/chrome/gameinit.yaml mods/ra/chrome/ingame.yaml + mods/ra/chrome/ingame-chat.yaml mods/ra/chrome/mainmenu.yaml mods/ra/chrome/settings.yaml mods/ra/chrome/lobby.yaml diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index b8d9962df6..bff601d868 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -54,6 +54,7 @@ Assemblies: ChromeLayout: mods/d2k/chrome/gameinit.yaml mods/ra/chrome/ingame.yaml + mods/ra/chrome/ingame-chat.yaml mods/d2k/chrome/mainmenu.yaml mods/ra/chrome/settings.yaml mods/d2k/chrome/lobby.yaml @@ -114,4 +115,4 @@ Fonts: Size:10 TinyBold: Font:FreeSansBold.ttf - Size:10 \ No newline at end of file + Size:10 diff --git a/mods/ra-classic/mod.yaml b/mods/ra-classic/mod.yaml index abfb9d720c..9c0d6ce510 100644 --- a/mods/ra-classic/mod.yaml +++ b/mods/ra-classic/mod.yaml @@ -56,6 +56,7 @@ Assemblies: ChromeLayout: mods/ra/chrome/gameinit.yaml mods/ra/chrome/ingame.yaml + mods/ra/chrome/ingame-chat.yaml mods/ra/chrome/mainmenu.yaml mods/ra/chrome/settings.yaml mods/ra/chrome/lobby.yaml diff --git a/mods/ra/chrome/ingame-chat.yaml b/mods/ra/chrome/ingame-chat.yaml new file mode 100644 index 0000000000..f2f987bad9 --- /dev/null +++ b/mods/ra/chrome/ingame-chat.yaml @@ -0,0 +1,71 @@ +Container@CHAT_PANEL: + X:(WINDOW_RIGHT - WIDTH) / 2 + Y:WINDOW_BOTTOM - HEIGHT - 15 + Width:550 + Height:180 + Logic:IngameChatLogic + Children: + Container@CHAT_OVERLAY: + X:0 + Y:0 + Width:PARENT_RIGHT + Height:PARENT_BOTTOM-30 + Visible: false + Children: + ChatDisplay@CHAT_DISPLAY: + X:0 + Y:0 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + DrawBackground: False + RemoveTime:250 + UseContrast: yes + Container@CHAT_CHROME: + X:0 + Y:0 + Width:PARENT_RIGHT + Height:PARENT_BOTTOM + Children: + Button@CHAT_MODE: + X:0 + Y:PARENT_BOTTOM - HEIGHT + Width: 50 + Height: 25 + Text: Team + Font: Bold + TextField@CHAT_TEXTFIELD: + X:55 + Y:PARENT_BOTTOM - HEIGHT + Width:465 + Height:25 + Button@CHAT_CLOSE: + X:525 + Y:PARENT_BOTTOM - HEIGHT + Width: 25 + Height: 25 + Text: X + Font: Bold + ScrollPanel@CHAT_SCROLLPANEL: + X:0 + Y:PARENT_BOTTOM - HEIGHT - 30 + Width:550 + Height:150 + ItemSpacing:1 + Children: + Container@CHAT_TEMPLATE: + X:2 + Y:0 + Width:PARENT_RIGHT-27 + Height:16 + Children: + Label@NAME: + X:3 + Width:50 + Height:15 + VAlign:Top + Label@TEXT: + X:10 + Width:PARENT_RIGHT - 60 + Height:15 + WordWrap:true + VAlign:Top diff --git a/mods/ra/chrome/ingame.yaml b/mods/ra/chrome/ingame.yaml index 0818a2410d..805353b4a9 100644 --- a/mods/ra/chrome/ingame.yaml +++ b/mods/ra/chrome/ingame.yaml @@ -206,20 +206,6 @@ Container@INGAME_ROOT: Text:Close Font:Bold Key:escape - ChatDisplay@CHAT_DISPLAY: - X:250 - Y:WINDOW_BOTTOM - HEIGHT - 30 - Width: 760 - Height: 200 - DrawBackground: False - RemoveTime:250 - UseContrast: yes - ChatEntry@CHAT_ENTRY: - X:250 - Y:WINDOW_BOTTOM - HEIGHT - Width: 760 - Height: 30 - UseContrast: yes Background@PERF_BG: ClickThrough:true Background:dialog4 @@ -373,20 +359,6 @@ Container@OBSERVER_ROOT: Height:25 Text:Abort Mission Font:Bold - ChatDisplay@CHAT_DISPLAY: - X:250 - Y:WINDOW_BOTTOM - HEIGHT - 30 - Width: 760 - Height: 200 - DrawBackground: False - RemoveTime:250 - UseContrast: yes - ChatEntry@CHAT_ENTRY: - X:250 - Y:WINDOW_BOTTOM - HEIGHT - Width: 760 - Height: 30 - UseContrast: yes Background@PERF_BG: ClickThrough:true Background:dialog4 diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 5863a6f47c..01fe43e4ab 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -55,6 +55,7 @@ Assemblies: ChromeLayout: mods/ra/chrome/gameinit.yaml mods/ra/chrome/ingame.yaml + mods/ra/chrome/ingame-chat.yaml mods/ra/chrome/mainmenu.yaml mods/ra/chrome/settings.yaml mods/ra/chrome/lobby.yaml From 54a59afde0ef2f42e387687e0d08595b9fb7047f Mon Sep 17 00:00:00 2001 From: Sascha Biedermann Date: Thu, 28 Mar 2013 23:57:46 +0100 Subject: [PATCH 2/2] fixed typo --- OpenRA.Game/Network/Session.cs | 2 +- OpenRA.Game/Network/UnitOrders.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Network/Session.cs b/OpenRA.Game/Network/Session.cs index bee4e6c7e8..917c4eda49 100644 --- a/OpenRA.Game/Network/Session.cs +++ b/OpenRA.Game/Network/Session.cs @@ -59,7 +59,7 @@ namespace OpenRA.Network public string Bot; // Bot type, null for real clients public bool IsAdmin; public bool IsReady { get { return State == ClientState.Ready; } } - public bool IsObeserver { get { return Slot == null; } } + public bool IsObserver { get { return Slot == null; } } } public class Slot diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 3f0a9d096c..a9c340e869 100755 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -44,7 +44,7 @@ namespace OpenRA.Network { var player = world != null ? world.FindPlayerByClient(client) : null; var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : ""; - suffix = client.IsObeserver ? " (Spectator)" : suffix; + suffix = client.IsObserver ? " (Spectator)" : suffix; Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString); } else