Files
OpenRA/OpenRA.Mods.Common/Widgets/Logic/Ingame/ObserverShroudSelectorLogic.cs
2021-05-08 22:20:59 +02:00

222 lines
6.8 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2020 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, 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.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Lint;
using OpenRA.Network;
using OpenRA.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
[ChromeLogicArgsHotkeys("CombinedViewKey", "WorldViewKey")]
public class ObserverShroudSelectorLogic : ChromeLogic
{
readonly CameraOption combined, disableShroud;
readonly IOrderedEnumerable<IGrouping<int, CameraOption>> teams;
readonly bool limitViews;
readonly HotkeyReference combinedViewKey = new HotkeyReference();
readonly HotkeyReference worldViewKey = new HotkeyReference();
readonly World world;
CameraOption selected;
LabelWidget shroudLabel;
class CameraOption
{
public readonly Player Player;
public readonly string Label;
public readonly Color Color;
public readonly string Faction;
public readonly Func<bool> IsSelected;
public readonly Action OnClick;
public CameraOption(ObserverShroudSelectorLogic logic, Player p)
{
Player = p;
Label = p.PlayerName;
Color = p.Color;
Faction = p.Faction.InternalName;
IsSelected = () => p.World.RenderPlayer == p;
OnClick = () =>
{
p.World.RenderPlayer = p;
logic.selected = this;
p.World.Selection.Clear();
WidgetUtils.BindPlayerNameAndStatus(logic.shroudLabel, p);
};
}
public CameraOption(ObserverShroudSelectorLogic logic, World w, string label, Player p)
{
Player = p;
Label = label;
Color = Color.White;
Faction = null;
IsSelected = () => w.RenderPlayer == p;
OnClick = () => { w.RenderPlayer = p; logic.selected = this; };
}
}
[ObjectCreator.UseCtor]
public ObserverShroudSelectorLogic(Widget widget, ModData modData, World world, WorldRenderer worldRenderer, Dictionary<string, MiniYaml> logicArgs)
{
this.world = world;
if (logicArgs.TryGetValue("CombinedViewKey", out var yaml))
combinedViewKey = modData.Hotkeys[yaml.Value];
if (logicArgs.TryGetValue("WorldViewKey", out yaml))
worldViewKey = modData.Hotkeys[yaml.Value];
limitViews = world.Map.Visibility.HasFlag(MapVisibility.MissionSelector);
var groups = new Dictionary<string, IEnumerable<CameraOption>>();
combined = new CameraOption(this, world, "All Players", world.Players.First(p => p.InternalName == "Everyone"));
disableShroud = new CameraOption(this, world, "Disable Shroud", null);
if (!limitViews)
groups.Add("Other", new List<CameraOption>() { combined, disableShroud });
teams = world.Players.Where(p => !p.NonCombatant && p.Playable)
.Select(p => new CameraOption(this, p))
.GroupBy(p => (world.LobbyInfo.ClientWithIndex(p.Player.ClientIndex) ?? new Session.Client()).Team)
.OrderBy(g => g.Key);
var noTeams = teams.Count() == 1;
foreach (var t in teams)
{
var label = noTeams ? "Players" : t.Key == 0 ? "No Team" : $"Team {t.Key}";
groups.Add(label, t);
}
var shroudSelector = widget.Get<DropDownButtonWidget>("SHROUD_SELECTOR");
shroudSelector.OnMouseDown = _ =>
{
Func<CameraOption, ScrollItemWidget, ScrollItemWidget> setupItem = (option, template) =>
{
var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick);
var showFlag = option.Faction != null;
var label = item.Get<LabelWidget>("LABEL");
label.IsVisible = () => showFlag;
label.GetColor = () => option.Color;
if (showFlag)
WidgetUtils.BindPlayerNameAndStatus(label, option.Player);
else
label.GetText = () => option.Label;
var flag = item.Get<ImageWidget>("FLAG");
flag.IsVisible = () => showFlag;
flag.GetImageCollection = () => "flags";
flag.GetImageName = () => option.Faction;
var labelAlt = item.Get<LabelWidget>("NOFLAG_LABEL");
labelAlt.IsVisible = () => !showFlag;
labelAlt.GetText = () => option.Label;
labelAlt.GetColor = () => option.Color;
return item;
};
shroudSelector.ShowDropDown("SPECTATOR_DROPDOWN_TEMPLATE", 400, groups, setupItem);
};
shroudLabel = shroudSelector.Get<LabelWidget>("LABEL");
shroudLabel.IsVisible = () => selected.Faction != null;
shroudLabel.GetText = () => selected.Label;
shroudLabel.GetColor = () => selected.Color;
var shroudFlag = shroudSelector.Get<ImageWidget>("FLAG");
shroudFlag.IsVisible = () => selected.Faction != null;
shroudFlag.GetImageCollection = () => "flags";
shroudFlag.GetImageName = () => selected.Faction;
var shroudLabelAlt = shroudSelector.Get<LabelWidget>("NOFLAG_LABEL");
shroudLabelAlt.IsVisible = () => selected.Faction == null;
shroudLabelAlt.GetText = () => selected.Label;
shroudLabelAlt.GetColor = () => selected.Color;
var keyhandler = shroudSelector.Get<LogicKeyListenerWidget>("SHROUD_KEYHANDLER");
keyhandler.AddHandler(HandleKeyPress);
selected = limitViews ? groups.First().Value.First() : world.WorldActor.Owner.Shroud.ExploreMapEnabled ? combined : disableShroud;
selected.OnClick();
// Enable zooming out to fractional zoom levels
worldRenderer.Viewport.UnlockMinimumZoom(0.5f);
}
public bool HandleKeyPress(KeyInput e)
{
if (e.Event == KeyInputEvent.Down && !e.IsRepeat)
{
if (combinedViewKey.IsActivatedBy(e) && !limitViews)
{
selected = combined;
selected.OnClick();
return true;
}
if (worldViewKey.IsActivatedBy(e) && !limitViews)
{
selected = disableShroud;
selected.OnClick();
return true;
}
if (e.Key >= Keycode.NUMBER_0 && e.Key <= Keycode.NUMBER_9)
{
var key = (int)e.Key - (int)Keycode.NUMBER_0;
var team = teams.Where(t => t.Key == key).SelectMany(s => s);
if (!team.Any())
return false;
if (e.Modifiers == Modifiers.Shift)
team = team.Reverse();
selected = team.SkipWhile(t => t.Player != selected.Player).Skip(1).FirstOrDefault() ?? team.FirstOrDefault();
selected.OnClick();
return true;
}
}
return false;
}
public override void Tick()
{
// Fix the selector if something else has changed the render player
if (selected != null && world.RenderPlayer != selected.Player)
{
if (combined.Player == world.RenderPlayer)
combined.OnClick();
else if (disableShroud.Player == world.RenderPlayer)
disableShroud.OnClick();
else
foreach (var group in teams)
foreach (var option in group)
if (option.Player == world.RenderPlayer)
option.OnClick();
}
}
}
}