using System.Linq; using Content.Client.UserInterface.Controls; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.Containers.ItemSlots; using Content.Shared.Kitchen; using Content.Shared.Kitchen.Components; using Content.Shared.Kitchen.EntitySystems; using Content.Shared.Power.EntitySystems; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; namespace Content.Client.Kitchen.UI; [GenerateTypedNameReferences] public sealed partial class GrinderMenu : FancyWindow { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly ItemSlotsSystem _slots = default!; private readonly SharedPowerReceiverSystem _power = default!; private readonly SharedReagentGrinderSystem _grinder = default!; private readonly SharedSolutionContainerSystem _solutionContainer = default!; private readonly Dictionary _chamberVisualContents = new(); private EntityUid _owner; public event Action? OnToggleAuto; public event Action? OnGrind; public event Action? OnJuice; public event Action? OnEjectAll; public event Action? OnEjectBeaker; public event Action? OnEjectChamber; public GrinderMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _slots = _entityManager.System(); _power = _entityManager.System(); _grinder = _entityManager.System(); _solutionContainer = _entityManager.System(); AutoModeButton.OnPressed += _ => OnToggleAuto?.Invoke(); GrindButton.OnPressed += _ => OnGrind?.Invoke(); JuiceButton.OnPressed += _ => OnJuice?.Invoke(); ChamberContentBox.EjectButton.OnPressed += _ => OnEjectAll?.Invoke(); BeakerContentBox.EjectButton.OnPressed += _ => OnEjectBeaker?.Invoke(); ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected; BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None; } private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args) { OnEjectChamber?.Invoke(_chamberVisualContents[args.ItemIndex]); } public void SetEntity(EntityUid owner) { _owner = owner; UpdateUi(); } public void UpdateUi() { if (!_entityManager.TryGetComponent(_owner, out var grinderComp)) return; var active = _grinder.IsActive((_owner, grinderComp)); var beaker = _slots.GetItemOrNull(_owner, ReagentGrinderComponent.BeakerSlotId); var powered = _power.IsPowered(_owner); var hasInput = grinderComp.InputContainer.ContainedEntities.Any(); var canGrind = hasInput && grinderComp.InputContainer.ContainedEntities.All(x => _grinder.CanGrind(x)); var canJuice = hasInput && grinderComp.InputContainer.ContainedEntities.All(x => _grinder.CanJuice(x)); BeakerContentBox.EjectButton.Disabled = active || !beaker.HasValue; ChamberContentBox.EjectButton.Disabled = active || !hasInput; GrindButton.Disabled = active || !canGrind || !powered || !beaker.HasValue; JuiceButton.Disabled = active || !canJuice || !powered || !beaker.HasValue; GrindButton.Modulate = grinderComp.Program == GrinderProgram.Grind ? Color.Green : Color.White; JuiceButton.Modulate = grinderComp.Program == GrinderProgram.Juice ? Color.Green : Color.White; AutoModeButton.Text = grinderComp.AutoMode switch { GrinderAutoMode.Grind => Loc.GetString("grinder-menu-grind-button"), GrinderAutoMode.Juice => Loc.GetString("grinder-menu-juice-button"), _ => Loc.GetString("grinder-menu-auto-button-off"), }; //Refresh chamber contents _chamberVisualContents.Clear(); ChamberContentBox.BoxContents.Clear(); foreach (var entity in grinderComp.InputContainer.ContainedEntities) { // TODO: Replace with SpriteView var texture = _entityManager.GetComponent(entity).Icon?.Default; var solidItem = ChamberContentBox.BoxContents.AddItem(_entityManager.GetComponent(entity).EntityName, texture); var solidIndex = ChamberContentBox.BoxContents.IndexOf(solidItem); _chamberVisualContents.Add(solidIndex, entity); } //Refresh beaker contents BeakerContentBox.BoxContents.Clear(); //if no beaker is attached use this guard to prevent hitting a null reference. if (!beaker.HasValue || !_solutionContainer.TryGetFitsInDispenser(beaker.Value, out _, out var reagents)) return; //Looks like we have a beaker attached. if (!reagents.Any()) { BeakerContentBox.BoxContents.AddItem(Loc.GetString("grinder-menu-beaker-content-box-is-empty")); } else { foreach (var (reagent, quantity) in reagents) { var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto) ? $"{quantity} {proto.LocalizedName}" : "???"; BeakerContentBox.BoxContents.AddItem(reagentName); } } } }