closes #2874: improved ingame chat

This commit is contained in:
Sascha Biedermann
2013-03-28 18:39:26 +01:00
parent b4a2489874
commit 1eb7c62c62
16 changed files with 255 additions and 61 deletions

View File

@@ -210,7 +210,7 @@ namespace OpenRA
var map = modData.PrepareMap(mapUID); var map = modData.PrepareMap(mapUID);
viewport = new Viewport(new int2(Renderer.Resolution), map.Bounds, Renderer); 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); worldRenderer = new WorldRenderer(orderManager.world);
if (orderManager.GameStarted) return; if (orderManager.GameStarted) return;

View File

@@ -59,6 +59,7 @@ namespace OpenRA.Network
public string Bot; // Bot type, null for real clients public string Bot; // Bot type, null for real clients
public bool IsAdmin; public bool IsAdmin;
public bool IsReady { get { return State == ClientState.Ready; } } public bool IsReady { get { return State == ClientState.Ready; } }
public bool IsObeserver { get { return Slot == null; } }
} }
public class Slot public class Slot

View File

@@ -44,6 +44,7 @@ namespace OpenRA.Network
{ {
var player = world != null ? world.FindPlayerByClient(client) : null; var player = world != null ? world.FindPlayerByClient(client) : null;
var suffix = (player != null && player.WinState == WinState.Lost) ? " (Dead)" : ""; 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); Game.AddChatLine(client.ColorRamp.GetColor(0), client.Name + suffix, order.TargetString);
} }
else else

View File

@@ -31,6 +31,7 @@ namespace OpenRA.Widgets
public Func<bool> OnEnterKey = () => false; public Func<bool> OnEnterKey = () => false;
public Func<bool> OnTabKey = () => false; public Func<bool> OnTabKey = () => false;
public Func<bool> OnEscKey = () => false;
public Action OnLoseFocus = () => { }; public Action OnLoseFocus = () => { };
public int CursorPosition { get; protected set; } public int CursorPosition { get; protected set; }
@@ -121,6 +122,9 @@ namespace OpenRA.Widgets
if (e.KeyName == "tab" && OnTabKey()) if (e.KeyName == "tab" && OnTabKey())
return true; return true;
if (e.KeyName == "escape" && OnEscKey())
return true;
if (e.KeyName == "left") if (e.KeyName == "left")
{ {
if (CursorPosition > 0) if (CursorPosition > 0)

View File

@@ -403,6 +403,8 @@ namespace OpenRA.Widgets
public override string GetCursor(int2 pos) { return null; } public override string GetCursor(int2 pos) { return null; }
public override Widget Clone() { return new ContainerWidget(this); } public override Widget Clone() { return new ContainerWidget(this); }
public Func<KeyInput, bool> OnKeyPress = _ => false;
public override bool HandleKeyPress(KeyInput e) { return OnKeyPress(e); }
} }
public class WidgetArgs : Dictionary<string, object> public class WidgetArgs : Dictionary<string, object>

View File

@@ -40,7 +40,7 @@ namespace OpenRA
public void AddPlayer(Player p) { Players.Add(p); } public void AddPlayer(Player p) { Players.Add(p); }
public Player LocalPlayer { get; private set; } public Player LocalPlayer { get; private set; }
public readonly Shroud LocalShroud; public readonly Shroud LocalShroud;
public bool Observer { get { return LocalPlayer == null; } }
public Player RenderedPlayer; public Player RenderedPlayer;
public Shroud RenderedShroud { get { return RenderedPlayer != null ? RenderedPlayer.Shroud : LocalShroud; } } 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; this.orderManager = orderManager;
orderGenerator_ = new UnitOrderGenerator(); orderGenerator_ = new UnitOrderGenerator();
Map = map; Map = map;

View File

@@ -375,6 +375,7 @@
<Compile Include="Widgets\Logic\DiplomacyLogic.cs" /> <Compile Include="Widgets\Logic\DiplomacyLogic.cs" />
<Compile Include="Widgets\Logic\DirectConnectLogic.cs" /> <Compile Include="Widgets\Logic\DirectConnectLogic.cs" />
<Compile Include="Widgets\Logic\DownloadPackagesLogic.cs" /> <Compile Include="Widgets\Logic\DownloadPackagesLogic.cs" />
<Compile Include="Widgets\Logic\IngameChatLogic.cs" />
<Compile Include="Widgets\Logic\IngameChromeLogic.cs" /> <Compile Include="Widgets\Logic\IngameChromeLogic.cs" />
<Compile Include="Widgets\Logic\IngameObserverChromeLogic.cs" /> <Compile Include="Widgets\Logic\IngameObserverChromeLogic.cs" />
<Compile Include="Widgets\Logic\LobbyLogic.cs" /> <Compile Include="Widgets\Logic\LobbyLogic.cs" />

View File

@@ -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<ContainerWidget>("CHAT_OVERLAY");
ChatOverlayDisplay = ChatOverlay.Get<ChatDisplayWidget>("CHAT_DISPLAY");
ChatOverlay.Visible = false;
ChatChrome = chatPanel.Get<ContainerWidget>("CHAT_CHROME");
ChatChrome.Visible = true;
var chatMode = ChatChrome.Get<ButtonWidget>("CHAT_MODE");
chatMode.GetText = () => TeamChat ? "Team" : "All";
chatMode.OnClick = () => TeamChat = !TeamChat;
ChatText = ChatChrome.Get<TextFieldWidget>("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<ButtonWidget>("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<ScrollPanelWidget>("CHAT_SCROLLPANEL");
ChatTemplate = ChatScrollPanel.Get<ContainerWidget>("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<LabelWidget>("NAME");
var textLabel = template.Get<LabelWidget>("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);
}
}
}

View File

@@ -22,9 +22,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public IngameChromeLogic(World world) public IngameChromeLogic(World world)
{ {
Game.AddChatLine += AddChatLine;
Game.BeforeGameStart += UnregisterEvents;
var r = Ui.Root; var r = Ui.Root;
gameRoot = r.Get("INGAME_ROOT"); gameRoot = r.Get("INGAME_ROOT");
var optionsBG = gameRoot.Get("INGAME_OPTIONS_BG"); var optionsBG = gameRoot.Get("INGAME_OPTIONS_BG");
@@ -58,8 +55,10 @@ namespace OpenRA.Mods.RA.Widgets.Logic
moneybin.Get<OrderButtonWidget>("POWER_DOWN").GetKey = _ => Game.Settings.Keys.PowerDownKey; moneybin.Get<OrderButtonWidget>("POWER_DOWN").GetKey = _ => Game.Settings.Keys.PowerDownKey;
moneybin.Get<OrderButtonWidget>("REPAIR").GetKey = _ => Game.Settings.Keys.RepairKey; moneybin.Get<OrderButtonWidget>("REPAIR").GetKey = _ => Game.Settings.Keys.RepairKey;
optionsBG.Get<ButtonWidget>("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world); var chatPanel = Game.LoadWidget(world, "CHAT_PANEL", Ui.Root, new WidgetArgs());
gameRoot.AddChild(chatPanel);
optionsBG.Get<ButtonWidget>("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world);
optionsBG.Get<ButtonWidget>("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU"); optionsBG.Get<ButtonWidget>("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU");
optionsBG.Get<ButtonWidget>("MUSIC").OnClick = () => Ui.OpenWindow("MUSIC_MENU"); optionsBG.Get<ButtonWidget>("MUSIC").OnClick = () => Ui.OpenWindow("MUSIC_MENU");
optionsBG.Get<ButtonWidget>("RESUME").OnClick = () => optionsBG.Get<ButtonWidget>("RESUME").OnClick = () =>
@@ -110,16 +109,5 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Ui.CloseWindow(); Ui.CloseWindow();
Ui.OpenWindow("MAINMENU_BG"); Ui.OpenWindow("MAINMENU_BG");
} }
void UnregisterEvents()
{
Game.AddChatLine -= AddChatLine;
Game.BeforeGameStart -= UnregisterEvents;
}
void AddChatLine(Color c, string from, string text)
{
gameRoot.Get<ChatDisplayWidget>("CHAT_DISPLAY").AddLine(c, from, text);
}
} }
} }

View File

@@ -10,6 +10,7 @@
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Widgets; using OpenRA.Widgets;
using OpenRA.Network;
using System; using System;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
@@ -24,9 +25,6 @@ namespace OpenRA.Mods.RA.Widgets.Logic
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public IngameObserverChromeLogic(World world) public IngameObserverChromeLogic(World world)
{ {
Game.AddChatLine += AddChatLine;
Game.BeforeGameStart += UnregisterEvents;
var r = Ui.Root; var r = Ui.Root;
gameRoot = r.Get("OBSERVER_ROOT"); gameRoot = r.Get("OBSERVER_ROOT");
var optionsBG = gameRoot.Get("INGAME_OPTIONS_BG"); var optionsBG = gameRoot.Get("INGAME_OPTIONS_BG");
@@ -59,6 +57,12 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Ui.Root.Get<ButtonWidget>("INGAME_STATS_BUTTON").OnClick = () => gameRoot.Get("OBSERVER_STATS").Visible ^= true; Ui.Root.Get<ButtonWidget>("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<DropDownButtonWidget>("SHROUD_SELECTOR"); var shroudSelector = Ui.Root.GetOrNull<DropDownButtonWidget>("SHROUD_SELECTOR");
if (shroudSelector != null) 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<ChatDisplayWidget>("CHAT_DISPLAY").AddLine(c, from, text);
}
class DropDownOption class DropDownOption
{ {
public string Title; public string Title;

View File

@@ -65,6 +65,7 @@ Assemblies:
ChromeLayout: ChromeLayout:
mods/ra/chrome/gameinit.yaml mods/ra/chrome/gameinit.yaml
mods/ra/chrome/ingame.yaml mods/ra/chrome/ingame.yaml
mods/ra/chrome/ingame-chat.yaml
mods/ra/chrome/mainmenu.yaml mods/ra/chrome/mainmenu.yaml
mods/ra/chrome/settings.yaml mods/ra/chrome/settings.yaml
mods/ra/chrome/lobby.yaml mods/ra/chrome/lobby.yaml

View File

@@ -54,6 +54,7 @@ Assemblies:
ChromeLayout: ChromeLayout:
mods/d2k/chrome/gameinit.yaml mods/d2k/chrome/gameinit.yaml
mods/ra/chrome/ingame.yaml mods/ra/chrome/ingame.yaml
mods/ra/chrome/ingame-chat.yaml
mods/d2k/chrome/mainmenu.yaml mods/d2k/chrome/mainmenu.yaml
mods/ra/chrome/settings.yaml mods/ra/chrome/settings.yaml
mods/d2k/chrome/lobby.yaml mods/d2k/chrome/lobby.yaml
@@ -114,4 +115,4 @@ Fonts:
Size:10 Size:10
TinyBold: TinyBold:
Font:FreeSansBold.ttf Font:FreeSansBold.ttf
Size:10 Size:10

View File

@@ -56,6 +56,7 @@ Assemblies:
ChromeLayout: ChromeLayout:
mods/ra/chrome/gameinit.yaml mods/ra/chrome/gameinit.yaml
mods/ra/chrome/ingame.yaml mods/ra/chrome/ingame.yaml
mods/ra/chrome/ingame-chat.yaml
mods/ra/chrome/mainmenu.yaml mods/ra/chrome/mainmenu.yaml
mods/ra/chrome/settings.yaml mods/ra/chrome/settings.yaml
mods/ra/chrome/lobby.yaml mods/ra/chrome/lobby.yaml

View File

@@ -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

View File

@@ -206,20 +206,6 @@ Container@INGAME_ROOT:
Text:Close Text:Close
Font:Bold Font:Bold
Key:escape 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: Background@PERF_BG:
ClickThrough:true ClickThrough:true
Background:dialog4 Background:dialog4
@@ -373,20 +359,6 @@ Container@OBSERVER_ROOT:
Height:25 Height:25
Text:Abort Mission Text:Abort Mission
Font:Bold 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: Background@PERF_BG:
ClickThrough:true ClickThrough:true
Background:dialog4 Background:dialog4

View File

@@ -55,6 +55,7 @@ Assemblies:
ChromeLayout: ChromeLayout:
mods/ra/chrome/gameinit.yaml mods/ra/chrome/gameinit.yaml
mods/ra/chrome/ingame.yaml mods/ra/chrome/ingame.yaml
mods/ra/chrome/ingame-chat.yaml
mods/ra/chrome/mainmenu.yaml mods/ra/chrome/mainmenu.yaml
mods/ra/chrome/settings.yaml mods/ra/chrome/settings.yaml
mods/ra/chrome/lobby.yaml mods/ra/chrome/lobby.yaml