187 lines
7.5 KiB
C#
187 lines
7.5 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using Content.Client.Stylesheets;
|
|
using Content.Client.UserInterface.Controls;
|
|
using Content.Shared._DV.CCVars;
|
|
using Content.Shared._DV.CosmicCult.Components;
|
|
using Content.Shared._DV.CosmicCult.Prototypes;
|
|
using Content.Shared._DV.CosmicCult;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.GameObjects;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.Player;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Configuration;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Client._DV.CosmicCult.UI.Monument;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class MonumentMenu : FancyWindow
|
|
{
|
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
[Dependency] private readonly IEntityManager _ent = default!;
|
|
[Dependency] private readonly IPlayerManager _player = default!;
|
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
|
|
private readonly SpriteSystem _sprite;
|
|
|
|
// All glyph prototypes
|
|
private readonly IEnumerable<GlyphPrototype> _glyphPrototypes;
|
|
// All influence prototypes
|
|
private readonly IEnumerable<InfluencePrototype> _influencePrototypes;
|
|
private readonly ButtonGroup _glyphButtonGroup;
|
|
private ProtoId<GlyphPrototype> _selectedGlyphProtoId = string.Empty;
|
|
private HashSet<ProtoId<GlyphPrototype>> _unlockedGlyphProtoIds = [];
|
|
public Action<ProtoId<GlyphPrototype>>? OnSelectGlyphButtonPressed;
|
|
public Action? OnRemoveGlyphButtonPressed;
|
|
|
|
public Action<ProtoId<InfluencePrototype>>? OnGainButtonPressed;
|
|
private int _entropyPerCultist = 0;
|
|
|
|
public MonumentMenu()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
IoCManager.InjectDependencies(this);
|
|
_sprite = _ent.System<SpriteSystem>();
|
|
|
|
_glyphPrototypes = _proto.EnumeratePrototypes<GlyphPrototype>()
|
|
.OrderBy(glyph => Loc.GetString(glyph.Name));
|
|
_influencePrototypes = _proto.EnumeratePrototypes<InfluencePrototype>();
|
|
|
|
_glyphButtonGroup = new ButtonGroup();
|
|
|
|
RemoveGlyphButton.OnPressed += _ => OnRemoveGlyphButtonPressed?.Invoke();
|
|
SelectGlyphButton.OnPressed += _ => OnSelectGlyphButtonPressed?.Invoke(_selectedGlyphProtoId);
|
|
|
|
_cfg.OnValueChanged(DCCVars.CosmicCultistEntropyValue, entropy =>
|
|
{
|
|
_entropyPerCultist = entropy;
|
|
},
|
|
invokeImmediately: true);
|
|
}
|
|
|
|
public void UpdateState(MonumentBuiState state)
|
|
{
|
|
_selectedGlyphProtoId = state.SelectedGlyph;
|
|
_unlockedGlyphProtoIds = state.UnlockedGlyphs;
|
|
|
|
CultProgressBar.BackgroundStyleBoxOverride = new StyleBoxFlat { BackgroundColor = new Color(15, 17, 30) };
|
|
CultProgressBar.ForegroundStyleBoxOverride = new StyleBoxFlat { BackgroundColor = new Color(91, 62, 124) };
|
|
|
|
UpdateBar(state);
|
|
UpdateEntropy(state);
|
|
UpdateGlyphs();
|
|
UpdateInfluences(state);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the progress bar
|
|
/// </summary>
|
|
private void UpdateBar(MonumentBuiState state)
|
|
{
|
|
var percentComplete = 100f * ((float)state.CurrentProgress / state.TargetProgress);
|
|
|
|
percentComplete = Math.Min(percentComplete, 100f);
|
|
|
|
CultProgressBar.Value = percentComplete;
|
|
|
|
ProgressBarPercentage.Text = Loc.GetString("monument-interface-progress-bar", ("percentage", percentComplete.ToString("0")));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the entropy fields
|
|
/// </summary>
|
|
private void UpdateEntropy(MonumentBuiState state)
|
|
{
|
|
var availableEntropy = -1;
|
|
if (_ent.TryGetComponent<CosmicCultComponent>(_player.LocalEntity, out var cultComp))
|
|
{
|
|
availableEntropy = cultComp.EntropyBudget;
|
|
}
|
|
|
|
var entropyToNextStage = Math.Max(state.TargetProgress - state.CurrentProgress, 0);
|
|
var min = entropyToNextStage == 0 ? 0 : 1; //I have no idea what to call this. makes it so that it shows 0 crew for the final stage but at least one at all other times
|
|
var crewToNextStage = (int)Math.Max(Math.Round((double)entropyToNextStage / _entropyPerCultist, MidpointRounding.ToPositiveInfinity), min); //force it to be at least one
|
|
|
|
AvailableEntropy.Text = Loc.GetString("monument-interface-entropy-value", ("infused", availableEntropy));
|
|
EntropyUntilNextStage.Text = Loc.GetString("monument-interface-entropy-value", ("infused", entropyToNextStage.ToString()));
|
|
CrewToConvertUntilNextStage.Text = crewToNextStage.ToString();
|
|
}
|
|
|
|
// Update all the glyph buttons
|
|
private void UpdateGlyphs()
|
|
{
|
|
GlyphContainer.RemoveAllChildren();
|
|
foreach (var glyph in _glyphPrototypes)
|
|
{
|
|
var boxContainer = new BoxContainer();
|
|
var unlocked = _unlockedGlyphProtoIds.Contains(glyph.ID);
|
|
var button = new Button
|
|
{
|
|
HorizontalExpand = true,
|
|
StyleClasses = { StyleBase.ButtonSquare },
|
|
ToolTip = Loc.GetString(glyph.Tooltip),
|
|
Group = _glyphButtonGroup,
|
|
Pressed = glyph.ID == _selectedGlyphProtoId,
|
|
Disabled = !unlocked,
|
|
Modulate = !unlocked ? Color.Gray : Color.White,
|
|
};
|
|
button.OnPressed += _ => _selectedGlyphProtoId = glyph.ID;
|
|
var glyphIcon = new TextureRect
|
|
{
|
|
Texture = _sprite.Frame0(glyph.Icon),
|
|
TextureScale = new Vector2(2f, 2f),
|
|
Stretch = TextureRect.StretchMode.KeepCentered,
|
|
};
|
|
button.AddChild(glyphIcon);
|
|
boxContainer.AddChild(button);
|
|
GlyphContainer.AddChild(boxContainer);
|
|
}
|
|
}
|
|
|
|
// Update all the influence thingies
|
|
private void UpdateInfluences(MonumentBuiState state)
|
|
{
|
|
InfluencesContainer.RemoveAllChildren();
|
|
|
|
var influenceUIBoxes = new List<InfluenceUIBox>();
|
|
foreach (var influence in _influencePrototypes)
|
|
{
|
|
var uiBoxState = GetUIBoxStateForInfluence(influence, state);
|
|
var influenceBox = new InfluenceUIBox(influence, uiBoxState);
|
|
influenceUIBoxes.Add(influenceBox);
|
|
influenceBox.OnGainButtonPressed += () => OnGainButtonPressed?.Invoke(influence.ID);
|
|
}
|
|
|
|
//sort the list of UI boxes by state (locked -> owned -> not enough entropy -> enough entropy)
|
|
//then sort alphabetically within those categories
|
|
foreach (var box in influenceUIBoxes.OrderBy(box => box.State).ThenBy(box => box.Proto.ID))
|
|
{
|
|
InfluencesContainer.AddChild(box);
|
|
}
|
|
}
|
|
|
|
private InfluenceUIBox.InfluenceUIBoxState GetUIBoxStateForInfluence(InfluencePrototype influence, MonumentBuiState state)
|
|
{
|
|
if (!_ent.TryGetComponent<CosmicCultComponent>(_player.LocalEntity, out var cultComp))
|
|
return InfluenceUIBox.InfluenceUIBoxState.Locked; //early return with locked if there's somehow no cult comp
|
|
|
|
var unlocked = cultComp.UnlockedInfluences.Contains(influence.ID);
|
|
var owned = cultComp.OwnedInfluences.Contains(influence);
|
|
|
|
//more verbose than it needs to be, but it reads nicer
|
|
if (owned)
|
|
return InfluenceUIBox.InfluenceUIBoxState.Owned;
|
|
|
|
if (unlocked)
|
|
{
|
|
//if it's unlocked, do we have enough entropy to buy it?
|
|
return influence.Cost > cultComp.EntropyBudget ? InfluenceUIBox.InfluenceUIBoxState.UnlockedAndNotEnoughEntropy : InfluenceUIBox.InfluenceUIBoxState.UnlockedAndEnoughEntropy;
|
|
}
|
|
|
|
return InfluenceUIBox.InfluenceUIBoxState.Locked;
|
|
}
|
|
}
|