using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Client.GameObjects.Components.Items;
using Content.Client.Utility;
using Content.Shared.GameObjects.Components.Items;
using Content.Shared.Input;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface
{
public class HandsGui : Control
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
private readonly Texture _leftHandTexture;
private readonly Texture _middleHandTexture;
private readonly Texture _rightHandTexture;
private readonly ItemStatusPanel _topPanel;
private readonly HBoxContainer _guiContainer;
private readonly VBoxContainer _handsColumn;
private readonly HBoxContainer _handsContainer;
public HandsGui()
{
IoCManager.InjectDependencies(this);
AddChild(_guiContainer = new HBoxContainer
{
SeparationOverride = 0,
HorizontalAlignment = HAlignment.Center,
Children =
{
(_handsColumn = new VBoxContainer
{
Children =
{
(_topPanel = ItemStatusPanel.FromSide(HandLocation.Middle)),
(_handsContainer = new HBoxContainer{HorizontalAlignment = HAlignment.Center})
}
}),
}
});
_leftHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_l.png");
_middleHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_l.png");
_rightHandTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/hand_r.png");
}
private Texture HandTexture(HandLocation location)
{
switch (location)
{
case HandLocation.Left:
return _leftHandTexture;
case HandLocation.Middle:
return _middleHandTexture;
case HandLocation.Right:
return _rightHandTexture;
default:
throw new ArgumentOutOfRangeException(nameof(location), location, null);
}
}
///
/// Adds a new hand to this control
///
/// The hand to add to this control
///
/// The actual location of the button. The right hand is drawn
/// on the LEFT of the screen.
///
private void AddHand(Hand hand, HandLocation buttonLocation)
{
var buttonTexture = HandTexture(buttonLocation);
var storageTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/back.png");
var blockedTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/blocked.png");
var button = new HandButton(buttonTexture, storageTexture, blockedTexture, buttonLocation);
var slot = hand.Name;
button.OnPressed += args => HandKeyBindDown(args, slot);
button.OnStoragePressed += args => _OnStoragePressed(args, slot);
_handsContainer.AddChild(button);
hand.Button = button;
}
public void RemoveHand(Hand hand)
{
var button = hand.Button;
if (button != null)
{
_handsContainer.RemoveChild(button);
}
}
///
/// Gets the hands component controlling this gui
///
///
/// true if successful and false if failure
private bool TryGetHands([NotNullWhen(true)] out HandsComponent? hands)
{
hands = default;
var entity = _playerManager?.LocalPlayer?.ControlledEntity;
return entity != null && entity.TryGetComponent(out hands);
}
public void UpdateHandIcons()
{
if (Parent == null)
{
return;
}
UpdateDraw();
if (!TryGetHands(out var component))
{
return;
}
// TODO: Remove button on remove hand
var hands = component.Hands.OrderByDescending(x => x.Location).ToArray();
for (var i = 0; i < hands.Length; i++)
{
var hand = hands[i];
if (hand.Button == null)
{
AddHand(hand, hand.Location);
}
hand.Button!.Button.Texture = HandTexture(hand.Location);
hand.Button!.SetPositionInParent(i);
_itemSlotManager.SetItemSlot(hand.Button, hand.Entity);
hand.Button!.SetActiveHand(component.ActiveIndex == hand.Name);
}
}
private void HandKeyBindDown(GUIBoundKeyEventArgs args, string slotName)
{
if (!TryGetHands(out var hands))
{
return;
}
if (args.Function == ContentKeyFunctions.MouseMiddle)
{
hands.SendChangeHand(slotName);
args.Handle();
return;
}
var entity = hands.GetEntity(slotName);
if (entity == null)
{
if (args.Function == EngineKeyFunctions.UIClick && hands.ActiveIndex != slotName)
{
hands.SendChangeHand(slotName);
args.Handle();
}
return;
}
if (_itemSlotManager.OnButtonPressed(args, entity))
{
args.Handle();
return;
}
if (args.Function == EngineKeyFunctions.UIClick)
{
if (hands.ActiveIndex == slotName)
{
hands.UseActiveHand();
}
else
{
hands.AttackByInHand(slotName);
}
args.Handle();
}
}
private void _OnStoragePressed(GUIBoundKeyEventArgs args, string handIndex)
{
if (args.Function != EngineKeyFunctions.UIClick || !TryGetHands(out var hands))
{
return;
}
hands.ActivateItemInHand(handIndex);
}
private void UpdatePanels()
{
if (!TryGetHands(out var component))
{
return;
}
foreach (var hand in component.Hands)
{
_itemSlotManager.UpdateCooldown(hand.Button, hand.Entity);
}
_topPanel.Update(component.GetEntity(component.ActiveIndex));
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdatePanels();
}
}
}