708 lines
25 KiB
C#
708 lines
25 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright (c) The OpenRA Developers and Contributors
|
|
* 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, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using OpenRA.Graphics;
|
|
using OpenRA.Mods.Common.Traits;
|
|
using OpenRA.Network;
|
|
using OpenRA.Primitives;
|
|
using OpenRA.Traits;
|
|
using OpenRA.Widgets;
|
|
|
|
namespace OpenRA.Mods.Common.Widgets.Logic
|
|
{
|
|
public static class LobbyUtils
|
|
{
|
|
[FluentReference]
|
|
const string Open = "options-lobby-slot.open";
|
|
|
|
[FluentReference]
|
|
const string Closed = "options-lobby-slot.closed";
|
|
|
|
[FluentReference]
|
|
const string Bots = "options-lobby-slot.bots";
|
|
|
|
[FluentReference]
|
|
const string BotsDisabled = "options-lobby-slot.bots-disabled";
|
|
|
|
[FluentReference]
|
|
const string Slot = "options-lobby-slot.slot";
|
|
|
|
sealed class SlotDropDownOption
|
|
{
|
|
public readonly string Title;
|
|
public readonly string Order;
|
|
public readonly Func<bool> Selected;
|
|
|
|
public SlotDropDownOption(string title, string order, Func<bool> selected)
|
|
{
|
|
Title = title;
|
|
Order = order;
|
|
Selected = selected;
|
|
}
|
|
}
|
|
|
|
public static void ShowSlotDropDown(DropDownButtonWidget dropdown, Session.Slot slot,
|
|
Session.Client client, OrderManager orderManager, MapPreview map, ModData modData)
|
|
{
|
|
var open = FluentProvider.GetMessage(Open);
|
|
var closed = FluentProvider.GetMessage(Closed);
|
|
var options = new Dictionary<string, IEnumerable<SlotDropDownOption>>
|
|
{
|
|
{
|
|
FluentProvider.GetMessage(Slot), new List<SlotDropDownOption>
|
|
{
|
|
new(open, "slot_open " + slot.PlayerReference, () => !slot.Closed && client == null),
|
|
new(closed, "slot_close " + slot.PlayerReference, () => slot.Closed)
|
|
}
|
|
}
|
|
};
|
|
|
|
var bots = new List<SlotDropDownOption>();
|
|
if (slot.AllowBots)
|
|
{
|
|
foreach (var b in map.PlayerActorInfo.TraitInfos<IBotInfo>())
|
|
{
|
|
var botController = orderManager.LobbyInfo.Clients.FirstOrDefault(c => c.IsAdmin);
|
|
bots.Add(new SlotDropDownOption(FluentProvider.GetMessage(b.Name),
|
|
$"slot_bot {slot.PlayerReference} {botController.Index} {b.Type}",
|
|
() => client != null && client.Bot == b.Type));
|
|
}
|
|
}
|
|
|
|
options.Add(bots.Count > 0 ? FluentProvider.GetMessage(Bots) : FluentProvider.GetMessage(BotsDisabled), bots);
|
|
|
|
ScrollItemWidget SetupItem(SlotDropDownOption o, ScrollItemWidget itemTemplate)
|
|
{
|
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
|
o.Selected,
|
|
() => orderManager.IssueOrder(Order.Command(o.Order)));
|
|
item.Get<LabelWidget>("LABEL").GetText = () => o.Title;
|
|
return item;
|
|
}
|
|
|
|
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 180, options, SetupItem);
|
|
}
|
|
|
|
public static void ShowPlayerActionDropDown(DropDownButtonWidget dropdown,
|
|
Session.Client c, OrderManager orderManager, Widget lobby, Action before, Action after)
|
|
{
|
|
Action<bool> okPressed = tempBan => { orderManager.IssueOrder(Order.Command($"kick {c.Index} {tempBan}")); after(); };
|
|
var onClick = new Action(() =>
|
|
{
|
|
before();
|
|
|
|
Game.LoadWidget(null, "KICK_CLIENT_DIALOG", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs
|
|
{
|
|
{ "clientName", c.Name },
|
|
{ "okPressed", okPressed },
|
|
{ "cancelPressed", after }
|
|
});
|
|
});
|
|
|
|
var options = new List<DropDownOption>
|
|
{
|
|
new()
|
|
{
|
|
Title = "Kick",
|
|
OnClick = onClick
|
|
},
|
|
};
|
|
|
|
if (orderManager.LobbyInfo.GlobalSettings.Dedicated)
|
|
{
|
|
options.Add(new DropDownOption
|
|
{
|
|
Title = "Transfer Admin",
|
|
OnClick = () => orderManager.IssueOrder(Order.Command($"make_admin {c.Index}"))
|
|
});
|
|
}
|
|
|
|
if (!c.IsObserver && orderManager.LobbyInfo.GlobalSettings.AllowSpectators)
|
|
{
|
|
options.Add(new DropDownOption
|
|
{
|
|
Title = "Move to Spectator",
|
|
OnClick = () => orderManager.IssueOrder(Order.Command($"make_spectator {c.Index}"))
|
|
});
|
|
}
|
|
|
|
ScrollItemWidget SetupItem(DropDownOption o, ScrollItemWidget itemTemplate)
|
|
{
|
|
var item = ScrollItemWidget.Setup(itemTemplate, o.IsSelected, o.OnClick);
|
|
var labelWidget = item.Get<LabelWidget>("LABEL");
|
|
labelWidget.GetText = () => o.Title;
|
|
return item;
|
|
}
|
|
|
|
dropdown.ShowDropDown("PLAYERACTION_DROPDOWN_TEMPLATE", 167, options, SetupItem);
|
|
}
|
|
|
|
public static void ShowTeamDropDown(DropDownButtonWidget dropdown, Session.Client client,
|
|
OrderManager orderManager, int teamCount)
|
|
{
|
|
ScrollItemWidget SetupItem(int ii, ScrollItemWidget itemTemplate)
|
|
{
|
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
|
() => client.Team == ii,
|
|
() => orderManager.IssueOrder(Order.Command($"team {client.Index} {ii}")));
|
|
item.Get<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : ii.ToString(NumberFormatInfo.CurrentInfo);
|
|
return item;
|
|
}
|
|
|
|
var options = Enumerable.Range(0, teamCount + 1);
|
|
dropdown.ShowDropDown("TEAM_DROPDOWN_TEMPLATE", 150, options, SetupItem);
|
|
}
|
|
|
|
public static void ShowHandicapDropDown(DropDownButtonWidget dropdown, Session.Client client,
|
|
OrderManager orderManager)
|
|
{
|
|
ScrollItemWidget SetupItem(int ii, ScrollItemWidget itemTemplate)
|
|
{
|
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
|
() => client.Handicap == ii,
|
|
() => orderManager.IssueOrder(Order.Command($"handicap {client.Index} {ii}")));
|
|
|
|
var label = $"{ii}%";
|
|
item.Get<LabelWidget>("LABEL").GetText = () => label;
|
|
return item;
|
|
}
|
|
|
|
// Handicaps may be set between 0 - 95% in steps of 5%
|
|
var options = Enumerable.Range(0, 20).Select(i => 5 * i);
|
|
dropdown.ShowDropDown("TEAM_DROPDOWN_TEMPLATE", 150, options, SetupItem);
|
|
}
|
|
|
|
public static void ShowSpawnDropDown(DropDownButtonWidget dropdown, Session.Client client,
|
|
OrderManager orderManager, IEnumerable<int> spawnPoints)
|
|
{
|
|
ScrollItemWidget SetupItem(int ii, ScrollItemWidget itemTemplate)
|
|
{
|
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
|
() => client.SpawnPoint == ii,
|
|
() => SetSpawnPoint(orderManager, client, ii));
|
|
item.Get<LabelWidget>("LABEL").GetText = () => ii == 0 ? "-" : Convert.ToChar('A' - 1 + ii).ToString();
|
|
return item;
|
|
}
|
|
|
|
dropdown.ShowDropDown("SPAWN_DROPDOWN_TEMPLATE", 150, spawnPoints, SetupItem);
|
|
}
|
|
|
|
/// <summary>Splits a string into two parts on the first instance of a given token.</summary>
|
|
public static (string First, string Second) SplitOnFirstToken(string input, string token = "\n")
|
|
{
|
|
if (string.IsNullOrEmpty(input))
|
|
return (null, null);
|
|
|
|
var split = input.IndexOf(token, StringComparison.Ordinal);
|
|
var first = split > 0 ? input[..split] : input;
|
|
var second = split > 0 ? input[(split + token.Length)..] : null;
|
|
return (first, second);
|
|
}
|
|
|
|
public static void ShowFactionDropDown(DropDownButtonWidget dropdown, Session.Client client,
|
|
OrderManager orderManager, Dictionary<string, LobbyFaction> factions)
|
|
{
|
|
ScrollItemWidget SetupItem(string factionId, ScrollItemWidget itemTemplate)
|
|
{
|
|
var item = ScrollItemWidget.Setup(itemTemplate,
|
|
() => client.Faction == factionId,
|
|
() => orderManager.IssueOrder(Order.Command($"faction {client.Index} {factionId}")));
|
|
var faction = factions[factionId];
|
|
|
|
var label = item.Get<LabelWidget>("LABEL");
|
|
var labelText = WidgetUtils.TruncateText(FluentProvider.GetMessage(faction.Name), label.Bounds.Width, Game.Renderer.Fonts[label.Font]);
|
|
label.GetText = () => labelText;
|
|
|
|
var flag = item.Get<ImageWidget>("FLAG");
|
|
flag.GetImageCollection = () => "flags";
|
|
flag.GetImageName = () => factionId;
|
|
|
|
var description = faction.Description != null ? FluentProvider.GetMessage(faction.Description) : null;
|
|
var (text, desc) = SplitOnFirstToken(description);
|
|
item.GetTooltipText = () => text;
|
|
item.GetTooltipDesc = () => desc;
|
|
|
|
return item;
|
|
}
|
|
|
|
var options = factions.Where(f => f.Value.Selectable).GroupBy(f => f.Value.Side)
|
|
.ToDictionary(g => g.Key != null ? FluentProvider.GetMessage(g.Key) : "", g => g.Select(f => FluentProvider.GetMessage(f.Key)));
|
|
|
|
dropdown.ShowDropDown("FACTION_DROPDOWN_TEMPLATE", 154, options, SetupItem);
|
|
}
|
|
|
|
public static void SelectSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
|
|
{
|
|
if (orderManager.LocalClient.State == Session.ClientState.Ready)
|
|
return;
|
|
|
|
if (mi.Button == MouseButton.Left)
|
|
SelectPlayerSpawnPoint(orderManager, mapPreview, preview, mi);
|
|
|
|
if (mi.Button == MouseButton.Right)
|
|
ClearPlayerSpawnPoint(orderManager, mapPreview, preview, mi);
|
|
}
|
|
|
|
static void SelectPlayerSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
|
|
{
|
|
var selectedSpawn = DetermineSelectedSpawnPoint(mapPreview, preview, mi);
|
|
|
|
var locals = orderManager.LobbyInfo.Clients.Where(c => c.Index == orderManager.LocalClient.Index || (Game.IsHost && c.Bot != null));
|
|
var playerToMove = locals.FirstOrDefault(c => (selectedSpawn == 0) ^ (c.SpawnPoint == 0) && !c.IsObserver);
|
|
SetSpawnPoint(orderManager, playerToMove, selectedSpawn);
|
|
}
|
|
|
|
static void ClearPlayerSpawnPoint(OrderManager orderManager, MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
|
|
{
|
|
var selectedSpawn = DetermineSelectedSpawnPoint(mapPreview, preview, mi);
|
|
if (Game.IsHost || orderManager.LobbyInfo.Clients.FirstOrDefault(cc => cc.SpawnPoint == selectedSpawn) == orderManager.LocalClient)
|
|
orderManager.IssueOrder(Order.Command($"clear_spawn {selectedSpawn}"));
|
|
}
|
|
|
|
static int DetermineSelectedSpawnPoint(MapPreviewWidget mapPreview, MapPreview preview, MouseInput mi)
|
|
{
|
|
var spawnSize = ChromeProvider.GetImage("lobby-bits", "spawn-unclaimed").Size.XY;
|
|
var selectedSpawn = preview.SpawnPoints
|
|
.Select((sp, i) => (SpawnLocation: mapPreview.ConvertToPreview(sp, preview.GridType), Index: i))
|
|
.Where(a => ((a.SpawnLocation - mi.Location).ToFloat2() / spawnSize * 2).LengthSquared <= 1)
|
|
.Select(a => a.Index + 1)
|
|
.FirstOrDefault();
|
|
return selectedSpawn;
|
|
}
|
|
|
|
static void SetSpawnPoint(OrderManager orderManager, Session.Client playerToMove, int selectedSpawnPoint)
|
|
{
|
|
var owned =
|
|
orderManager.LobbyInfo.Clients.Any(c => c.SpawnPoint == selectedSpawnPoint) ||
|
|
orderManager.LobbyInfo.DisabledSpawnPoints.Contains(selectedSpawnPoint);
|
|
if (selectedSpawnPoint == 0 || !owned)
|
|
orderManager.IssueOrder(Order.Command($"spawn {(playerToMove ?? orderManager.LocalClient).Index} {selectedSpawnPoint}"));
|
|
}
|
|
|
|
public static List<int> AvailableSpawnPoints(int spawnPoints, Session lobbyInfo)
|
|
{
|
|
return Enumerable.Range(1, spawnPoints).Except(lobbyInfo.DisabledSpawnPoints).ToList();
|
|
}
|
|
|
|
public static bool InsufficientEnabledSpawnPoints(MapPreview map, Session lobbyInfo)
|
|
{
|
|
// If a map doesn't define spawn points we always have enough space
|
|
var spawnPoints = map.SpawnPoints.Length;
|
|
if (spawnPoints == 0)
|
|
return false;
|
|
|
|
return AvailableSpawnPoints(spawnPoints, lobbyInfo).Count < lobbyInfo.Clients.Count(c => !c.IsObserver);
|
|
}
|
|
|
|
public static Color LatencyColor(Session.Client client)
|
|
{
|
|
if (client == null)
|
|
return Color.Gray;
|
|
|
|
switch (client.ConnectionQuality)
|
|
{
|
|
case Session.ConnectionQuality.Good: return Color.LimeGreen;
|
|
case Session.ConnectionQuality.Moderate: return Color.Orange;
|
|
case Session.ConnectionQuality.Poor: return Color.Red;
|
|
default: return Color.Gray;
|
|
}
|
|
}
|
|
|
|
public static string LatencyDescription(Session.Client client)
|
|
{
|
|
if (client == null)
|
|
return "Unknown";
|
|
|
|
switch (client.ConnectionQuality)
|
|
{
|
|
case Session.ConnectionQuality.Good: return "Good";
|
|
case Session.ConnectionQuality.Moderate: return "Moderate";
|
|
case Session.ConnectionQuality.Poor: return "Poor";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
public static void SetupLatencyWidget(Widget parent, Session.Client c, OrderManager orderManager)
|
|
{
|
|
var visible = c != null && c.Bot == null;
|
|
var block = parent.GetOrNull("LATENCY");
|
|
if (block != null)
|
|
{
|
|
block.IsVisible = () => visible;
|
|
|
|
if (visible)
|
|
block.Get<ColorBlockWidget>("LATENCY_COLOR").GetColor = () => LatencyColor(c);
|
|
}
|
|
|
|
var tooltip = parent.Get<ClientTooltipRegionWidget>("LATENCY_REGION");
|
|
tooltip.IsVisible = () => visible;
|
|
if (visible)
|
|
tooltip.Bind(orderManager, null, c);
|
|
}
|
|
|
|
public static void SetupProfileWidget(Widget parent, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer)
|
|
{
|
|
var profile = parent.GetOrNull<ImageWidget>("PROFILE");
|
|
if (profile != null)
|
|
{
|
|
var imageName = c.IsBot ? "bot" :
|
|
c.IsAdmin ? "admin-" :
|
|
"player-";
|
|
|
|
if (!c.IsBot)
|
|
imageName += c.Fingerprint != null ? "registered" : "anonymous";
|
|
|
|
profile.GetImageName = () => imageName;
|
|
profile.IsVisible = () => true;
|
|
}
|
|
|
|
var profileTooltip = parent.GetOrNull<ClientTooltipRegionWidget>("PROFILE_TOOLTIP");
|
|
if (profileTooltip != null)
|
|
{
|
|
if (c.Fingerprint != null)
|
|
profileTooltip.Template = "REGISTERED_PLAYER_TOOLTIP";
|
|
|
|
if (c.IsBot)
|
|
profileTooltip.Template = "BOT_TOOLTIP";
|
|
|
|
profileTooltip.Bind(orderManager, worldRenderer, c);
|
|
|
|
profileTooltip.IsVisible = () => true;
|
|
}
|
|
}
|
|
|
|
public static void SetupEditableNameWidget(Widget parent, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer)
|
|
{
|
|
var name = parent.Get<TextFieldWidget>("NAME");
|
|
name.IsVisible = () => true;
|
|
name.IsDisabled = () => orderManager.LocalClient.IsReady;
|
|
|
|
name.Text = c.Name;
|
|
var escPressed = false;
|
|
name.OnLoseFocus = () =>
|
|
{
|
|
if (escPressed)
|
|
{
|
|
escPressed = false;
|
|
return;
|
|
}
|
|
|
|
name.Text = name.Text.Trim();
|
|
if (name.Text.Length == 0)
|
|
name.Text = c.Name;
|
|
else if (name.Text != c.Name)
|
|
{
|
|
name.Text = Settings.SanitizedPlayerName(name.Text);
|
|
orderManager.IssueOrder(Order.Command("name " + name.Text));
|
|
Game.Settings.Player.Name = name.Text;
|
|
Game.Settings.Save();
|
|
}
|
|
};
|
|
|
|
name.OnEnterKey = _ => { name.YieldKeyboardFocus(); return true; };
|
|
name.OnEscKey = _ =>
|
|
{
|
|
name.Text = c.Name;
|
|
escPressed = true;
|
|
name.YieldKeyboardFocus();
|
|
return true;
|
|
};
|
|
|
|
SetupProfileWidget(name, c, orderManager, worldRenderer);
|
|
|
|
HideChildWidget(parent, "SLOT_OPTIONS");
|
|
}
|
|
|
|
public static void SetupNameWidget(Widget parent, Session.Client c, OrderManager orderManager, WorldRenderer worldRenderer)
|
|
{
|
|
var label = parent.Get<LabelWidget>("NAME");
|
|
label.IsVisible = () => true;
|
|
var font = Game.Renderer.Fonts[label.Font];
|
|
var name = c.IsBot ? FluentProvider.GetMessage(c.Name) : c.Name;
|
|
var text = WidgetUtils.TruncateText(name, label.Bounds.Width, font);
|
|
label.GetText = () => text;
|
|
|
|
SetupProfileWidget(parent, c, orderManager, worldRenderer);
|
|
}
|
|
|
|
public static void SetupEditableSlotWidget(Widget parent, Session.Slot s, Session.Client c,
|
|
OrderManager orderManager, MapPreview map, ModData modData)
|
|
{
|
|
var slot = parent.Get<DropDownButtonWidget>("SLOT_OPTIONS");
|
|
slot.IsVisible = () => true;
|
|
slot.IsDisabled = () => orderManager.LocalClient.IsReady;
|
|
|
|
var truncated = new CachedTransform<string, string>(name =>
|
|
WidgetUtils.TruncateText(name, slot.Bounds.Width - slot.Bounds.Height - slot.LeftMargin - slot.RightMargin,
|
|
Game.Renderer.Fonts[slot.Font]));
|
|
|
|
var closed = FluentProvider.GetMessage(Closed);
|
|
var open = FluentProvider.GetMessage(Open);
|
|
slot.GetText = () => truncated.Update(c != null ?
|
|
c.IsBot ? FluentProvider.GetMessage(c.Name) : c.Name
|
|
: s.Closed ? closed : open);
|
|
|
|
slot.OnMouseDown = _ => ShowSlotDropDown(slot, s, c, orderManager, map, modData);
|
|
|
|
// Ensure Name selector (if present) is hidden
|
|
HideChildWidget(parent, "NAME");
|
|
}
|
|
|
|
public static void SetupSlotWidget(Widget parent, ModData modData, Session.Slot s, Session.Client c)
|
|
{
|
|
var name = parent.Get<LabelWidget>("NAME");
|
|
name.IsVisible = () => true;
|
|
name.GetText = () => c != null ? c.Name : s.Closed
|
|
? FluentProvider.GetMessage(Closed)
|
|
: FluentProvider.GetMessage(Open);
|
|
|
|
// Ensure Slot selector (if present) is hidden
|
|
HideChildWidget(parent, "SLOT_OPTIONS");
|
|
}
|
|
|
|
public static void SetupPlayerActionWidget(Widget parent, Session.Client c, OrderManager orderManager,
|
|
WorldRenderer worldRenderer, Widget lobby, Action before, Action after)
|
|
{
|
|
var slot = parent.Get<DropDownButtonWidget>("PLAYER_ACTION");
|
|
slot.IsVisible = () => Game.IsHost && c.Index != orderManager.LocalClient.Index;
|
|
slot.IsDisabled = () => orderManager.LocalClient.IsReady;
|
|
|
|
var truncated = new CachedTransform<string, string>(name =>
|
|
WidgetUtils.TruncateText(name, slot.Bounds.Width - slot.Bounds.Height - slot.LeftMargin - slot.RightMargin,
|
|
Game.Renderer.Fonts[slot.Font]));
|
|
|
|
slot.GetText = () => truncated.Update(c != null ? c.Name : string.Empty);
|
|
slot.OnMouseDown = _ => ShowPlayerActionDropDown(slot, c, orderManager, lobby, before, after);
|
|
|
|
SetupProfileWidget(slot, c, orderManager, worldRenderer);
|
|
|
|
// Ensure Name selector (if present) is hidden
|
|
HideChildWidget(parent, "NAME");
|
|
}
|
|
|
|
public static void SetupKickSpectatorsWidget(Widget parent, OrderManager orderManager, Widget lobby, Action before, Action after, bool skirmishMode)
|
|
{
|
|
var checkBox = parent.Get<CheckboxWidget>("TOGGLE_SPECTATORS");
|
|
checkBox.IsChecked = () => orderManager.LobbyInfo.GlobalSettings.AllowSpectators;
|
|
checkBox.IsVisible = () => orderManager.LocalClient.IsAdmin && !skirmishMode;
|
|
checkBox.IsDisabled = () => false;
|
|
|
|
void OkPressed()
|
|
{
|
|
orderManager.IssueOrder(Order.Command($"allow_spectators {!orderManager.LobbyInfo.GlobalSettings.AllowSpectators}"));
|
|
orderManager.IssueOrders(
|
|
orderManager.LobbyInfo.Clients.Where(
|
|
c => c.IsObserver && !c.IsAdmin).Select(
|
|
client => Order.Command($"kick {client.Index} {client.Name}")).ToArray());
|
|
|
|
after();
|
|
}
|
|
|
|
checkBox.OnClick = () =>
|
|
{
|
|
before();
|
|
|
|
var spectatorCount = orderManager.LobbyInfo.Clients.Count(c => c.IsObserver);
|
|
if (spectatorCount > 0)
|
|
{
|
|
Game.LoadWidget(null, "KICK_SPECTATORS_DIALOG", lobby.Get("TOP_PANELS_ROOT"), new WidgetArgs
|
|
{
|
|
{ "clientCount", spectatorCount },
|
|
{ "okPressed", OkPressed },
|
|
{ "cancelPressed", after }
|
|
});
|
|
}
|
|
else
|
|
{
|
|
orderManager.IssueOrder(Order.Command($"allow_spectators {!orderManager.LobbyInfo.GlobalSettings.AllowSpectators}"));
|
|
after();
|
|
}
|
|
};
|
|
}
|
|
|
|
public static void SetupEditableColorWidget(Widget parent, Session.Slot s, Session.Client c,
|
|
OrderManager orderManager, WorldRenderer worldRenderer, IColorPickerManagerInfo colorManager)
|
|
{
|
|
var colorDropdown = parent.Get<DropDownButtonWidget>("COLOR");
|
|
colorDropdown.IsDisabled = () => (s != null && s.LockColor) || orderManager.LocalClient.IsReady;
|
|
colorDropdown.OnMouseDown = _ => colorManager.ShowColorDropDown(colorDropdown, c.Color, c.Faction, worldRenderer, color =>
|
|
{
|
|
if (c == orderManager.LocalClient)
|
|
{
|
|
Game.Settings.Player.Color = color;
|
|
Game.Settings.Save();
|
|
}
|
|
|
|
orderManager.IssueOrder(Order.Command($"color {c.Index} {color}"));
|
|
});
|
|
|
|
SetupColorWidget(colorDropdown, c);
|
|
}
|
|
|
|
public static void SetupColorWidget(Widget parent, Session.Client c)
|
|
{
|
|
var color = parent.Get<ColorBlockWidget>("COLORBLOCK");
|
|
color.GetColor = () => c.Color;
|
|
}
|
|
|
|
public static void SetupEditableFactionWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager,
|
|
Dictionary<string, LobbyFaction> factions)
|
|
{
|
|
var dropdown = parent.Get<DropDownButtonWidget>("FACTION");
|
|
dropdown.IsDisabled = () => s.LockFaction || orderManager.LocalClient.IsReady;
|
|
dropdown.OnMouseDown = _ => ShowFactionDropDown(dropdown, c, orderManager, factions);
|
|
|
|
var description = factions[c.Faction].Description != null ? FluentProvider.GetMessage(factions[c.Faction].Description) : null;
|
|
var (text, desc) = SplitOnFirstToken(description);
|
|
dropdown.GetTooltipText = () => text;
|
|
dropdown.GetTooltipDesc = () => desc;
|
|
|
|
SetupFactionWidget(dropdown, c, factions);
|
|
}
|
|
|
|
public static void SetupFactionWidget(Widget parent, Session.Client c, Dictionary<string, LobbyFaction> factions)
|
|
{
|
|
var factionName = parent.Get<LabelWidget>("FACTIONNAME");
|
|
var font = Game.Renderer.Fonts[factionName.Font];
|
|
var truncated = new CachedTransform<string, string>(clientFaction =>
|
|
WidgetUtils.TruncateText(FluentProvider.GetMessage(factions[clientFaction].Name), factionName.Bounds.Width, font));
|
|
factionName.GetText = () => truncated.Update(c.Faction);
|
|
|
|
var factionFlag = parent.Get<ImageWidget>("FACTIONFLAG");
|
|
factionFlag.GetImageName = () => c.Faction;
|
|
factionFlag.GetImageCollection = () => "flags";
|
|
}
|
|
|
|
public static void SetupEditableTeamWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, MapPreview map)
|
|
{
|
|
var dropdown = parent.Get<DropDownButtonWidget>("TEAM_DROPDOWN");
|
|
dropdown.IsVisible = () => true;
|
|
dropdown.IsDisabled = () => s.LockTeam || orderManager.LocalClient.IsReady;
|
|
dropdown.OnMouseDown = _ => ShowTeamDropDown(dropdown, c, orderManager, map.PlayerCount);
|
|
dropdown.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(NumberFormatInfo.CurrentInfo);
|
|
|
|
HideChildWidget(parent, "TEAM");
|
|
}
|
|
|
|
public static void SetupTeamWidget(Widget parent, Session.Client c)
|
|
{
|
|
var team = parent.Get<LabelWidget>("TEAM");
|
|
team.IsVisible = () => true;
|
|
team.GetText = () => (c.Team == 0) ? "-" : c.Team.ToString(NumberFormatInfo.CurrentInfo);
|
|
HideChildWidget(parent, "TEAM_DROPDOWN");
|
|
}
|
|
|
|
public static void SetupEditableHandicapWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager)
|
|
{
|
|
var dropdown = parent.Get<DropDownButtonWidget>("HANDICAP_DROPDOWN");
|
|
dropdown.IsVisible = () => true;
|
|
dropdown.IsDisabled = () => s.LockHandicap || orderManager.LocalClient.IsReady;
|
|
dropdown.OnMouseDown = _ => ShowHandicapDropDown(dropdown, c, orderManager);
|
|
|
|
var handicapLabel = new CachedTransform<int, string>(h => $"{h}%");
|
|
dropdown.GetText = () => handicapLabel.Update(c.Handicap);
|
|
|
|
HideChildWidget(parent, "HANDICAP");
|
|
}
|
|
|
|
public static void SetupHandicapWidget(Widget parent, Session.Client c)
|
|
{
|
|
var team = parent.Get<LabelWidget>("HANDICAP");
|
|
team.IsVisible = () => true;
|
|
|
|
var handicapLabel = new CachedTransform<int, string>(h => $"{h}%");
|
|
team.GetText = () => handicapLabel.Update(c.Handicap);
|
|
HideChildWidget(parent, "HANDICAP_DROPDOWN");
|
|
}
|
|
|
|
public static void SetupEditableSpawnWidget(Widget parent, Session.Slot s, Session.Client c, OrderManager orderManager, MapPreview map)
|
|
{
|
|
var dropdown = parent.Get<DropDownButtonWidget>("SPAWN_DROPDOWN");
|
|
dropdown.IsVisible = () => true;
|
|
dropdown.IsDisabled = () => s.LockSpawn || orderManager.LocalClient.IsReady;
|
|
dropdown.OnMouseDown = _ =>
|
|
{
|
|
var spawnPoints = Enumerable.Range(0, map.SpawnPoints.Length + 1).Except(
|
|
orderManager.LobbyInfo.Clients.Where(
|
|
client => client != c && client.SpawnPoint != 0).Select(client => client.SpawnPoint))
|
|
.Except(orderManager.LobbyInfo.DisabledSpawnPoints);
|
|
ShowSpawnDropDown(dropdown, c, orderManager, spawnPoints);
|
|
};
|
|
dropdown.GetText = () => (c.SpawnPoint == 0) ? "-" : Convert.ToChar('A' - 1 + c.SpawnPoint).ToString();
|
|
|
|
HideChildWidget(parent, "SPAWN");
|
|
}
|
|
|
|
public static void SetupSpawnWidget(Widget parent, Session.Client c)
|
|
{
|
|
var spawn = parent.Get<LabelWidget>("SPAWN");
|
|
spawn.IsVisible = () => true;
|
|
spawn.GetText = () => (c.SpawnPoint == 0) ? "-" : Convert.ToChar('A' - 1 + c.SpawnPoint).ToString();
|
|
HideChildWidget(parent, "SPAWN_DROPDOWN");
|
|
}
|
|
|
|
public static void SetupEditableReadyWidget(Widget parent, Session.Client c, OrderManager orderManager, MapPreview map, bool isEnabled)
|
|
{
|
|
var status = parent.Get<CheckboxWidget>("STATUS_CHECKBOX");
|
|
status.IsVisible = () => true;
|
|
status.IsDisabled = () => c.Bot != null || map.Status != MapStatus.Available || !isEnabled;
|
|
if (c.Bot == null)
|
|
{
|
|
var isChecked = new PredictedCachedTransform<Session.Client, bool>(cc => cc.IsReady);
|
|
status.IsChecked = () => isChecked.Update(c);
|
|
status.OnClick = () =>
|
|
{
|
|
var state = isChecked.Update(c) ? Session.ClientState.NotReady : Session.ClientState.Ready;
|
|
orderManager.IssueOrder(Order.Command($"state {state}"));
|
|
isChecked.Predict(!c.IsReady);
|
|
};
|
|
}
|
|
else
|
|
status.IsChecked = () => true;
|
|
}
|
|
|
|
public static void SetupReadyWidget(Widget parent, Session.Client c)
|
|
{
|
|
parent.Get<ImageWidget>("STATUS_IMAGE").IsVisible = () => c.IsReady || c.Bot != null;
|
|
}
|
|
|
|
public static void HideReadyWidgets(Widget parent)
|
|
{
|
|
HideChildWidget(parent, "STATUS_CHECKBOX");
|
|
HideChildWidget(parent, "STATUS_IMAGE");
|
|
}
|
|
|
|
static void HideChildWidget(Widget parent, string widgetId)
|
|
{
|
|
var widget = parent.GetOrNull(widgetId);
|
|
if (widget != null)
|
|
widget.IsVisible = () => false;
|
|
}
|
|
}
|
|
|
|
sealed class ShowPlayerActionDropDownOption
|
|
{
|
|
public Action Click { get; set; }
|
|
public string Title;
|
|
public Func<bool> Selected = () => false;
|
|
|
|
public ShowPlayerActionDropDownOption(string title, Action click)
|
|
{
|
|
Click = click;
|
|
Title = title;
|
|
}
|
|
}
|
|
}
|