Files
OpenRA/OpenRA.Mods.Common/Widgets/Logic/EncyclopediaLogic.cs
2024-11-03 16:52:47 +02:00

185 lines
5.6 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.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Primitives;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
public class EncyclopediaLogic : ChromeLogic
{
readonly World world;
readonly ModData modData;
readonly ScrollPanelWidget descriptionPanel;
readonly LabelWidget descriptionLabel;
readonly SpriteFont descriptionFont;
readonly ScrollPanelWidget actorList;
readonly ScrollItemWidget headerTemplate;
readonly ScrollItemWidget template;
readonly ActorPreviewWidget previewWidget;
ActorInfo selectedActor;
ScrollItemWidget firstItem;
[ObjectCreator.UseCtor]
public EncyclopediaLogic(Widget widget, World world, ModData modData, Action onExit)
{
this.world = world;
this.modData = modData;
actorList = widget.Get<ScrollPanelWidget>("ACTOR_LIST");
headerTemplate = widget.Get<ScrollItemWidget>("HEADER");
template = widget.Get<ScrollItemWidget>("TEMPLATE");
widget.Get("ACTOR_INFO").IsVisible = () => selectedActor != null;
previewWidget = widget.Get<ActorPreviewWidget>("ACTOR_PREVIEW");
previewWidget.IsVisible = () => selectedActor != null;
descriptionPanel = widget.Get<ScrollPanelWidget>("ACTOR_DESCRIPTION_PANEL");
descriptionLabel = descriptionPanel.Get<LabelWidget>("ACTOR_DESCRIPTION");
descriptionFont = Game.Renderer.Fonts[descriptionLabel.Font];
actorList.RemoveChildren();
var actorEncyclopediaPair = GetFilteredActorEncyclopediaPairs();
var categories = actorEncyclopediaPair.Select(a => a.Value.Category).Distinct().
OrderBy(string.IsNullOrWhiteSpace).ThenBy(s => s);
foreach (var category in categories)
{
CreateActorGroup(category, actorEncyclopediaPair
.Where(a => a.Value.Category == category)
.OrderBy(a => a.Value.Order)
.Select(a => a.Key));
}
widget.Get<ButtonWidget>("BACK_BUTTON").OnClick = () =>
{
Game.Disconnect();
Ui.CloseWindow();
onExit();
};
}
IReadOnlyCollection<KeyValuePair<ActorInfo, EncyclopediaInfo>> GetFilteredActorEncyclopediaPairs()
{
var actors = new List<KeyValuePair<ActorInfo, EncyclopediaInfo>>();
foreach (var actor in modData.DefaultRules.Actors.Values)
{
if (actor.TraitInfos<IRenderActorPreviewSpritesInfo>().Count == 0)
continue;
var statistics = actor.TraitInfoOrDefault<UpdatesPlayerStatisticsInfo>();
if (statistics != null && !string.IsNullOrEmpty(statistics.OverrideActor))
continue;
var encyclopedia = actor.TraitInfoOrDefault<EncyclopediaInfo>();
if (encyclopedia == null)
continue;
actors.Add(new KeyValuePair<ActorInfo, EncyclopediaInfo>(actor, encyclopedia));
}
return actors;
}
void CreateActorGroup(string title, IEnumerable<ActorInfo> actors)
{
var header = ScrollItemWidget.Setup(headerTemplate, () => false, () => { });
header.Get<LabelWidget>("LABEL").GetText = () => title;
actorList.AddChild(header);
foreach (var actor in actors)
{
var item = ScrollItemWidget.Setup(template,
() => selectedActor != null && selectedActor.Name == actor.Name,
() => SelectActor(actor));
var label = item.Get<LabelWithTooltipWidget>("TITLE");
var name = actor.TraitInfos<TooltipInfo>().FirstOrDefault(info => info.EnabledByDefault)?.Name;
if (!string.IsNullOrEmpty(name))
WidgetUtils.TruncateLabelToTooltip(label, FluentProvider.GetMessage(name));
if (firstItem == null)
{
firstItem = item;
SelectActor(actor);
}
actorList.AddChild(item);
}
}
void SelectActor(ActorInfo actor)
{
selectedActor = actor;
var typeDictionary = new TypeDictionary()
{
new OwnerInit(world.WorldActor.Owner),
new FactionInit(world.WorldActor.Owner.PlayerReference.Faction)
};
foreach (var actorPreviewInit in actor.TraitInfos<IActorPreviewInitInfo>())
foreach (var inits in actorPreviewInit.ActorPreviewInits(actor, ActorPreviewType.ColorPicker))
typeDictionary.Add(inits);
previewWidget.SetPreview(actor, typeDictionary);
var text = "";
var buildable = actor.TraitInfoOrDefault<BuildableInfo>();
if (buildable != null)
{
var prerequisites = buildable.Prerequisites
.Select(a => ActorName(modData.DefaultRules, a))
.Where(s => !s.StartsWith('~') && !s.StartsWith('!'))
.ToList();
if (prerequisites.Count != 0)
text += $"Requires {prerequisites.JoinWith(", ")}\n\n";
}
var info = actor.TraitInfoOrDefault<EncyclopediaInfo>();
if (info != null && !string.IsNullOrEmpty(info.Description))
text += WidgetUtils.WrapText(FluentProvider.GetMessage(info.Description) + "\n\n", descriptionLabel.Bounds.Width, descriptionFont);
var height = descriptionFont.Measure(text).Y;
descriptionLabel.GetText = () => text;
descriptionLabel.Bounds.Height = height;
descriptionPanel.Layout.AdjustChildren();
descriptionPanel.ScrollToTop();
}
static string ActorName(Ruleset rules, string name)
{
if (rules.Actors.TryGetValue(name.ToLowerInvariant(), out var actor))
{
var actorTooltip = actor.TraitInfos<TooltipInfo>().FirstOrDefault(info => info.EnabledByDefault);
if (actorTooltip != null)
return FluentProvider.GetMessage(actorTooltip.Name);
}
return name;
}
}
}