Files
tbd-station-14/Content.Client/Implants/UI/ChameleonControllerMenu.xaml.cs
beck-thompson 05fac53de6 Chameleon controller implant (Clothing fast switch) (#33887)
* Add the chameleon controller implant

* address the issues (Git please dont kill me)

* Address the review and fix some merge conflicts!

* Cleanup

* Add use delay

* Silly mistakes

* Making a PR at 2 am: Gone wrong

* Predict use delay and disable the buttons until you can choose another

* First phase custom clothing

* Better system, now relays to agent id and mindshield. Chameleon loadouts are a lot better to work with as well

* Address the review! No more evil goto

* Slams way is better I should have read more closely xD

* Some of the jobs

* Add to Cargo, CentComm, Service, Passenger, Ninja, Cluwne, Wizard + Minor changes to existing; Add chameleon to bandanas, medals, jugsuits and HUDs

* Add everything else

* Fix test

* Job name

* This looks better

* Add department organization

* Minor cleanup

* Added some mindshields

* Remove redudent comment and change funcion name to be clearer

* Fix cluwne outfit

* fix merge conflicts

---------

Co-authored-by: SlamBamActionman <slambamactionman@gmail.com>
2025-05-30 12:07:25 +02:00

158 lines
5.2 KiB
C#

using System.Linq;
using System.Numerics;
using Content.Client.Roles;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Implants;
using Content.Shared.StatusIcon;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Implants.UI;
[GenerateTypedNameReferences]
public sealed partial class ChameleonControllerMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
private readonly SpriteSystem _sprite;
private readonly JobSystem _job;
// List of all the job protos that you can select!
private IEnumerable<ChameleonOutfitPrototype> _outfits;
// Lock the UI until this time
public DateTime? _lockedUntil;
private static readonly ProtoId<JobIconPrototype> UnknownIcon = "JobIconUnknown";
private static readonly LocId UnknownDepartment = "department-Unknown";
public event Action<ProtoId<ChameleonOutfitPrototype>>? OnJobSelected;
public ChameleonControllerMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_sprite = _entityManager.System<SpriteSystem>();
_job = _entityManager.System<JobSystem>();
_outfits = _prototypeManager.EnumeratePrototypes<ChameleonOutfitPrototype>();
UpdateGrid();
}
/// <summary>
/// Fill the grid with the correct job icons and buttons.
/// </summary>
/// <param name="disabled">Set to true to disable all the buttons.</param>
public void UpdateGrid(bool disabled = false)
{
Grid.RemoveAllChildren();
// Dictionary to easily put outfits in departments.
// Department name -> UI element holding that department.
var departments = new Dictionary<string, BoxContainer>();
departments.Add(UnknownDepartment, CreateDepartment(UnknownDepartment));
// Go through every outfit and add them to the correct department.
foreach (var outfit in _outfits)
{
_prototypeManager.TryIndex(outfit.Job, out var jobProto);
var name = outfit.LoadoutName ?? outfit.Name ?? jobProto?.Name ?? "Prototype has no name or job.";
var jobIconId = outfit.Icon ?? jobProto?.Icon ?? UnknownIcon;
var jobIconProto = _prototypeManager.Index(jobIconId);
var outfitButton = CreateOutfitButton(disabled, name, jobIconProto, outfit.ID);
if (outfit.Job != null && _job.TryGetLowestWeightDepartment(outfit.Job, out var departmentPrototype))
{
if (!departments.ContainsKey(departmentPrototype.Name))
departments.Add(departmentPrototype.Name, CreateDepartment(departmentPrototype.Name));
departments[departmentPrototype.Name].AddChild(outfitButton);
}
else
{
departments[UnknownDepartment].AddChild(outfitButton);
}
}
// Sort the departments by their weight.
var departmentList = departments.ToList();
departmentList.Sort((a, b) => a.Value.ChildCount.CompareTo(b.Value.ChildCount));
// Actually add the departments to the window.
foreach (var department in departmentList)
{
Grid.AddChild(department.Value);
}
}
private BoxContainer CreateDepartment(string name)
{
var departmentContainer = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
};
departmentContainer.AddChild(new Label
{
Text = Loc.GetString(name),
});
return departmentContainer;
}
private BoxContainer CreateOutfitButton(bool disabled, string name, JobIconPrototype jobIconProto, ProtoId<ChameleonOutfitPrototype> outfitProto)
{
var outfitButton = new BoxContainer();
var button = new Button
{
HorizontalExpand = true,
StyleClasses = {StyleBase.ButtonSquare},
ToolTip = Loc.GetString(name),
Text = Loc.GetString(name),
Margin = new Thickness(0, 0, 15, 0),
Disabled = disabled,
};
var jobIconTexture = new TextureRect
{
Texture = _sprite.Frame0(jobIconProto.Icon),
TextureScale = new Vector2(2.5f, 2.5f),
Stretch = TextureRect.StretchMode.KeepCentered,
Margin = new Thickness(0, 0, 5, 0),
};
outfitButton.AddChild(jobIconTexture);
outfitButton.AddChild(button);
button.OnPressed += _ => JobButtonPressed(outfitProto);
return outfitButton;
}
private void JobButtonPressed(ProtoId<ChameleonOutfitPrototype> outfit)
{
OnJobSelected?.Invoke(outfit);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_lockedUntil == null || DateTime.Now < _lockedUntil)
return;
_lockedUntil = null;
UpdateGrid();
}
}