using Barotrauma.Extensions;
using Barotrauma.Items.Components;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace Barotrauma
{
    partial class CharacterInventory : Inventory
    {        
        public enum Layout
        {
            Default,
            Left, 
            Right,
            Center
        }
        
        private enum QuickUseAction
        {
            None,
            Equip,
            Unequip,
            Drop,
            TakeFromContainer,
            TakeFromCharacter,
            PutToContainer,
            PutToCharacter,
            PutToEquippedItem,
            UseTreatment,
        }

        private static Dictionary<InvSlotType, Sprite> limbSlotIcons;
        public static Dictionary<InvSlotType, Sprite> LimbSlotIcons
        {
            get
            {
                if (limbSlotIcons == null)
                {
                    limbSlotIcons = new Dictionary<InvSlotType, Sprite>();
                    foreach (InvSlotType invSlotType in Enum.GetValues(typeof(InvSlotType)))
                    {
                        var sprite = GUIStyle.GetComponentStyle($"InventorySlot.{invSlotType}")?.GetDefaultSprite();
                        if (sprite != null)
                        {
                            limbSlotIcons.Add(invSlotType, sprite);
                        }
                    }

                    int margin = 2;
                    AddIfMissing(InvSlotType.Headset, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(384 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
                    AddIfMissing(InvSlotType.InnerClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(512 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
                    AddIfMissing(InvSlotType.Card, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(640 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
                    AddIfMissing(InvSlotType.Head, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(896 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
                    AddIfMissing(InvSlotType.LeftHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(634, 0, 128, 128)));
                    AddIfMissing(InvSlotType.RightHand, new Sprite("Content/UI/InventoryUIAtlas.png", new Rectangle(762, 0, 128, 128)));
                    AddIfMissing(InvSlotType.OuterClothes, new Sprite("Content/UI/MainIconsAtlas.png", new Rectangle(256 + margin, 128 + margin, 128 - margin * 2, 128 - margin * 2)));
                    AddIfMissing(InvSlotType.Bag, new Sprite("Content/UI/CommandUIAtlas.png", new Rectangle(639, 926, 128,80)));

                    static void AddIfMissing(InvSlotType slotType, Sprite sprite)
                    {
                        limbSlotIcons.TryAdd(slotType, sprite);
                    }
                }
                return limbSlotIcons;
            }
        }

        public const InvSlotType PersonalSlots = InvSlotType.Card | InvSlotType.Bag | InvSlotType.Headset | InvSlotType.InnerClothes | InvSlotType.OuterClothes | InvSlotType.Head;

        private Point screenResolution;

        public Vector2[] SlotPositions;
        public static Point SlotSize;

        private Layout layout;
        public Layout CurrentLayout
        {
            get { return layout; }
            set
            {
                if (layout == value) { return; }
                layout = value;
                SetSlotPositions(layout);
            }
        }

        private Rectangle personalSlotArea;

        partial void InitProjSpecific(XElement element)
        {
            SlotPositions = new Vector2[SlotTypes.Length];
            CurrentLayout = Layout.Default;
            SetSlotPositions(layout);
        }

        protected override ItemInventory GetActiveEquippedSubInventory(int slotIndex)
        {
            Item item = slots[slotIndex].FirstOrDefault();
            if (item == null) { return null; }

            var container = item.GetComponent<ItemContainer>();
            if (container == null || !container.KeepOpenWhenEquippedBy(character))
            {
                return null;
            }
            return container.Inventory;
        }

        public override void CreateSlots()
        {
            visualSlots ??= new VisualSlot[capacity];

            float multiplier = UIScale * GUI.AspectRatioAdjustment;
            
            for (int i = 0; i < capacity; i++)
            {
                VisualSlot prevSlot = visualSlots[i];
                
                Sprite slotSprite = SlotSpriteSmall;
                Rectangle slotRect = new Rectangle(
                    (int)SlotPositions[i].X, 
                    (int)SlotPositions[i].Y,
                    (int)(slotSprite.size.X * multiplier), (int)(slotSprite.size.Y * multiplier));

                if (SlotTypes[i] == InvSlotType.HealthInterface &&
                    character.CharacterHealth?.InventorySlotContainer != null)
                {
                    slotRect.Width = slotRect.Height = (int)(character.CharacterHealth.InventorySlotContainer.Rect.Width * 1.2f);
                }
             
                ItemContainer itemContainer = slots[i].FirstOrDefault()?.GetComponent<ItemContainer>();
                if (itemContainer != null)
                {
                    if (itemContainer.InventoryTopSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryTopSprite.size.X * UIScale));
                    if (itemContainer.InventoryBottomSprite != null) slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryBottomSprite.size.X * UIScale));
                }                

                visualSlots[i] = new VisualSlot(slotRect)
                {
                    SubInventoryDir = Math.Sign(GameMain.GraphicsHeight / 2 - slotRect.Center.Y),
                    Disabled = false,
                    SlotSprite = slotSprite,
                    Color = SlotTypes[i] == InvSlotType.Any ? Color.White * 0.2f : Color.White * 0.4f
                };
                if (prevSlot != null)
                {
                    visualSlots[i].DrawOffset = prevSlot.DrawOffset;
                    visualSlots[i].Color = prevSlot.Color;
                    prevSlot.MoveBorderHighlight(visualSlots[i]);
                }
                if (selectedSlot?.ParentInventory == this && selectedSlot.SlotIndex == i)
                {
                    selectedSlot = new SlotReference(this, visualSlots[i], i, selectedSlot.IsSubSlot, selectedSlot.Inventory);
                }
            }

            AssignQuickUseNumKeys();

            highlightedSubInventorySlots.RemoveWhere(s => s.Inventory.OpenState <= 0.0f);
            foreach (var subSlot in highlightedSubInventorySlots)
            {
                if (subSlot.ParentInventory == this && subSlot.SlotIndex > 0 && subSlot.SlotIndex < visualSlots.Length)
                {
                    subSlot.Slot = visualSlots[subSlot.SlotIndex];
                }
            }

            screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
            CalculateBackgroundFrame();
        }

        protected override void CalculateBackgroundFrame()
        {
            Rectangle frame = Rectangle.Empty;
            for (int i = 0; i < capacity; i++)
            {
                if (HideSlot(i)) continue;
                if (frame == Rectangle.Empty)
                {
                    frame = visualSlots[i].Rect;
                    continue;
                }
                frame = Rectangle.Union(frame, visualSlots[i].Rect);
            }
            frame.Inflate(10, 30);
            frame.Location -= new Point(0, 25);
            BackgroundFrame = frame;
        }

        public override bool HideSlot(int i)
        {
            if (visualSlots[i].Disabled || (slots[i].HideIfEmpty && slots[i].Empty())) { return true; }

            if (SlotTypes[i] == InvSlotType.HealthInterface)
            {
                //hide health interface slot unless this character's health window is open
                if (CharacterHealth.OpenHealthWindow == null || Character.Controlled == null)
                {
                    return true;
                }
                if (character == Character.Controlled)
                {
                    bool ownHealthWindowOpen = CharacterHealth.OpenHealthWindow == Character.Controlled.CharacterHealth;
                    if (!ownHealthWindowOpen) { return true; }
                }
                else if (character == Character.Controlled.SelectedCharacter)
                {
                    bool otherCharacterHealthWindowOpen = CharacterHealth.OpenHealthWindow == Character.Controlled?.SelectedCharacter?.CharacterHealth;
                    if (!otherCharacterHealthWindowOpen) { return true; }
                    //can't access the health interface slot of a non-incapacitated player (bots are fine though)
                    if (character.IsPlayer && !character.IsIncapacitated) { return true; }
                }
            }

            if (layout == Layout.Default)
            {
                if (PersonalSlots.HasFlag(SlotTypes[i]) && !personalSlotArea.Contains(visualSlots[i].Rect.Center + visualSlots[i].DrawOffset.ToPoint())) { return true; }
            }

            Item item = slots[i].FirstOrDefault();

            //no need to draw the right hand slot if the item is in both hands
            if (item != null && SlotTypes[i] == InvSlotType.RightHand && IsInLimbSlot(item, InvSlotType.LeftHand))
            {
                return true;
            }

            //don't show the limb-specific slot if the item is also in an Any slot
            if (item != null && SlotTypes[i] != InvSlotType.Any)
            {
                if (IsInLimbSlot(item, InvSlotType.Any)) { return true; }
            }

            //don't draw equipment slots in wiring mode
            if (Screen.Selected == GameMain.SubEditorScreen && GameMain.SubEditorScreen.WiringMode)
            {
                if (SlotTypes[i] != InvSlotType.Any && SlotTypes[i] != InvSlotType.LeftHand && SlotTypes[i] != InvSlotType.RightHand)
                {
                    return true;
                }
            }

            return false;
        }

        public void RefreshSlotPositions()
        {
            SetSlotPositions(CurrentLayout);
        }

        private void SetSlotPositions(Layout layout)
        {
            int spacing = GUI.IntScale(5);

            SlotSize = (SlotSpriteSmall.size * UIScale * GUI.AspectRatioAdjustment).ToPoint();
            int bottomOffset = GetBottomOffset(multiplier: 2);
            int personalSlotY = GetVerticalOffsetFromBottom(multiplier: 2);

            if (visualSlots == null) { CreateSlots(); }
            if (visualSlots.None()) { return; }

            switch (layout)
            {
                case Layout.Default:
                    {
                        int personalSlotCount = SlotTypes.Count(s => PersonalSlots.HasFlag(s));
                        int normalSlotCount = SlotTypes.Count(s => !PersonalSlots.HasFlag(s) && s != InvSlotType.HealthInterface);

                        int x = GameMain.GraphicsWidth / 2 - normalSlotCount * (SlotSize.X + spacing) / 2;
                        int upperX = HUDLayoutSettings.BottomRightInfoArea.X - SlotSize.X - spacing;

                        //make sure the rightmost normal slot doesn't overlap with the personal slots
                        x -= Math.Max((x + normalSlotCount * (SlotSize.X + spacing)) - (upperX - personalSlotCount * (SlotSize.X + spacing)), 0);

                        int hideButtonSlotIndex = -1;
                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (PersonalSlots.HasFlag(SlotTypes[i]))
                            {
                                SlotPositions[i] = new Vector2(upperX, GameMain.GraphicsHeight - bottomOffset);
                                upperX -= SlotSize.X + spacing;
                                personalSlotArea = (hideButtonSlotIndex == -1) ? 
                                    new Rectangle(SlotPositions[i].ToPoint(), SlotSize) :
                                    Rectangle.Union(personalSlotArea, new Rectangle(SlotPositions[i].ToPoint(), SlotSize));
                                hideButtonSlotIndex = i;
                            }
                            else
                            {
                                SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
                                x += SlotSize.X + spacing;
                            }
                        }
                    }
                    break;
                case Layout.Right:
                    {
                        int x = HUDLayoutSettings.InventoryAreaLower.Right;
                        int personalSlotX = HUDLayoutSettings.InventoryAreaLower.Right - SlotSize.X - spacing;
                        for (int i = 0; i < visualSlots.Length; i++)
                        {
                            if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
                            if (PersonalSlots.HasFlag(SlotTypes[i]))
                            {
                                //upperX -= slotSize.X + spacing;
                            }
                            else
                            {
                                x -= SlotSize.X + spacing;
                            }
                        }

                        int lowerX = x;
                        int handSlotX = x;
                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
                            {
                                SlotPositions[i] = new Vector2(handSlotX, personalSlotY);
                                handSlotX += visualSlots[i].Rect.Width + spacing;
                                continue;
                            }

                            if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            if (PersonalSlots.HasFlag(SlotTypes[i]))
                            {
                                SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
                                personalSlotX -= visualSlots[i].Rect.Width + spacing;
                            }
                            else
                            {
                                SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
                                x += visualSlots[i].Rect.Width + spacing;
                            }
                        }

                        x = lowerX;
                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
                            x -= visualSlots[i].Rect.Width + spacing;
                            SlotPositions[i] = new Vector2(x, GameMain.GraphicsHeight - bottomOffset);
                        }
                    }
                    break;
                case Layout.Left:
                    {
                        int x = HUDLayoutSettings.InventoryAreaLower.X;
                        if (!GUI.IsUltrawide && GUI.IsHUDScaled)
                        {
                            // On non-ultra-wide aspect ratios, the inventories can easily overlap with each other, if there's any scaling.
                            // So let's offset the other inventory to the left.
                            const float margin = 100;
                            x -= HUDLayoutSettings.ChatBoxArea.Width - (int)margin;
                        }
                        int personalSlotX = x;
                        float y = GameMain.GraphicsHeight - bottomOffset;

                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand) { continue; }
                            if (PersonalSlots.HasFlag(SlotTypes[i]))
                            {
                                SlotPositions[i] = new Vector2(personalSlotX, personalSlotY);
                                personalSlotX += visualSlots[i].Rect.Width + spacing;
                            }
                            else
                            {
                                SlotPositions[i] = new Vector2(x, y);
                                x += visualSlots[i].Rect.Width + spacing;
                            }
                        }
                        int handSlotX = x - visualSlots[0].Rect.Width - spacing;
                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (SlotTypes[i] == InvSlotType.RightHand || SlotTypes[i] == InvSlotType.LeftHand)
                            {
                                bool rightSlot = SlotTypes[i] == InvSlotType.RightHand;
                                SlotPositions[i] = new Vector2(rightSlot ? handSlotX : handSlotX - visualSlots[0].Rect.Width - spacing, personalSlotY);
                                continue;
                            }
                            if (!HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            SlotPositions[i] = new Vector2(x, y);
                            x += visualSlots[i].Rect.Width + spacing;
                        }
                    }
                    break;
                case Layout.Center:
                    {
                        int columns = 5;
                        int startX = (GameMain.GraphicsWidth / 2) - (SlotSize.X * columns + spacing * (columns - 1)) / 2;
                        int startY = GameMain.GraphicsHeight / 2 - (SlotSize.Y * 2);
                        int x = startX, y = startY;
                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            if (SlotTypes[i] == InvSlotType.Card || SlotTypes[i] == InvSlotType.Headset || SlotTypes[i] == InvSlotType.InnerClothes)
                            {
                                SlotPositions[i] = new Vector2(x, y);
                                x += visualSlots[i].Rect.Width + spacing;
                            }
                        }
                        y += visualSlots[0].Rect.Height + spacing + ContainedIndicatorHeight + visualSlots[0].EquipButtonRect.Height;
                        x = startX;
                        int n = 0;
                        for (int i = 0; i < SlotPositions.Length; i++)
                        {
                            if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }
                            if (SlotTypes[i] != InvSlotType.Card && SlotTypes[i] != InvSlotType.Headset && SlotTypes[i] != InvSlotType.InnerClothes)
                            {
                                SlotPositions[i] = new Vector2(x, y);
                                x += visualSlots[i].Rect.Width + spacing;
                                n++;
                                if (n >= columns)
                                {
                                    x = startX;
                                    y += visualSlots[i].Rect.Height + spacing + ContainedIndicatorHeight + visualSlots[i].EquipButtonRect.Height;
                                    n = 0;
                                }
                            }
                        }
                    }
                    break;
            }

            if (character.CharacterHealth?.UseHealthWindow ?? false)
            {
                Vector2 pos = character.CharacterHealth.InventorySlotContainer.Rect.Location.ToVector2();
                for (int i = 0; i < capacity; i++)
                {
                    if (SlotTypes[i] != InvSlotType.HealthInterface) { continue; }
                    SlotPositions[i] = pos;
                    pos.Y += visualSlots[i].Rect.Height + spacing;
                }
            }

            CreateSlots();
            if (layout == Layout.Default)
            {
                HUDLayoutSettings.InventoryTopY = visualSlots[0].EquipButtonRect.Y - (int)(15 * GUI.Scale);
            }
            else
            {
                for (int i = 0; i < capacity; i++)
                {
                    visualSlots[i].DrawOffset = Vector2.Zero;
                }
            }
            
            int GetBottomOffset(int multiplier) => SlotSize.Y + spacing * multiplier + ContainedIndicatorHeight;
            int GetVerticalOffsetFromBottom(int multiplier) => GameMain.GraphicsHeight - (GetBottomOffset(multiplier) + spacing) * multiplier - (int)(UnequippedIndicator.size.Y * UIScale);
        }

        protected override void ControlInput(Camera cam)
        {
            base.ControlInput(cam);
            // Ignore the background frame of this object in purpose, because it encompasses half of the screen.
            if (highlightedSubInventorySlots.Any(i => i.Inventory != null && i.Inventory.BackgroundFrame.Contains(PlayerInput.MousePosition)))
            {
                cam.Freeze = true;
            }
        }

        private readonly static List<SlotReference> hideSubInventories = new List<SlotReference>();
        private readonly static List<SlotReference> tempHighlightedSubInventorySlots = new List<SlotReference>();

        public override void Update(float deltaTime, Camera cam, bool isSubInventory = false)
        {
            if (!AccessibleWhenAlive && !character.IsDead && !AccessibleByOwner)
            {
                syncItemsDelay = Math.Max(syncItemsDelay - deltaTime, 0.0f);
                doubleClickedItems.Clear();
                return;
            }

            base.Update(deltaTime, cam);

            bool hoverOnInventory = GUI.MouseOn == null &&
                ((selectedSlot != null && selectedSlot.IsSubSlot) || (DraggingItems.Any() && (DraggingSlot == null || !DraggingSlot.MouseOn())));
            if (CharacterHealth.OpenHealthWindow != null) { hoverOnInventory = true; }

            if (hoverOnInventory) { HideTimer = 0.5f; }
            if (HideTimer > 0.0f) { HideTimer -= deltaTime; }

            UpdateSlotInput();

            hideSubInventories.Clear();
            //remove highlighted subinventory slots that can no longer be accessed
            highlightedSubInventorySlots.RemoveWhere(s => 
                s.ParentInventory == this &&
                ((s.SlotIndex < 0 || s.SlotIndex >= slots.Length || slots[s.SlotIndex] == null) || (Character.Controlled != null && !Character.Controlled.CanAccessInventory(s.Inventory))));
            //remove highlighted subinventory slots that refer to items no longer in this inventory
            highlightedSubInventorySlots.RemoveWhere(s => s.Item != null && s.ParentInventory == this && s.Item.ParentInventory != this);
            //remove highlighted subinventory slots if we're dragging that item out of the inventory
            highlightedSubInventorySlots.RemoveWhere(s => s.Item != null && s.ParentInventory == this && DraggingItems.Contains(s.Item));

            tempHighlightedSubInventorySlots.Clear();
            tempHighlightedSubInventorySlots.AddRange(highlightedSubInventorySlots);
            foreach (var highlightedSubInventorySlot in tempHighlightedSubInventorySlots)
            {
                if (highlightedSubInventorySlot.ParentInventory == this)
                {
                    UpdateSubInventory(deltaTime, highlightedSubInventorySlot.SlotIndex, cam);
                }

                if (!highlightedSubInventorySlot.Inventory.IsInventoryHoverAvailable(character, null)) continue;

                Rectangle hoverArea = GetSubInventoryHoverArea(highlightedSubInventorySlot);
                if (highlightedSubInventorySlot.Inventory?.visualSlots == null || (!hoverArea.Contains(PlayerInput.MousePosition)))
                {
                    hideSubInventories.Add(highlightedSubInventorySlot);
                }
                else
                {
                    highlightedSubInventorySlot.Inventory.HideTimer = 1.0f;
                }
            }

            //activate the subinventory of the currently selected slot
            if (selectedSlot?.ParentInventory == this)
            {
                var subInventory = GetSubInventory(selectedSlot.SlotIndex);
                if (subInventory != null && subInventory.IsInventoryHoverAvailable(character, null))
                {
                    selectedSlot.Inventory = subInventory;
                    if (!highlightedSubInventorySlots.Any(s => s.Inventory == subInventory))
                    {
                        ShowSubInventory(selectedSlot, deltaTime, cam, hideSubInventories, false);
                    }
                }
            }

            // In sub editor we cannot hover over the slot because they are not rendered so we override it here
            if (Screen.Selected is SubEditorScreen subEditor && !subEditor.WiringMode)
            {
                for (int i = 0; i < visualSlots.Length; i++)
                {
                    var subInventory = GetSubInventory(i);
                    if (subInventory != null)
                    {
                        ShowSubInventory(new SlotReference(this, visualSlots[i], i, false, subInventory), deltaTime, cam, hideSubInventories, true);
                    }
                }
            }
                       
            foreach (var subInventorySlot in hideSubInventories)
            {
                if (subInventorySlot.Inventory == null) { continue; }
                subInventorySlot.Inventory.HideTimer -= deltaTime;
                if (subInventorySlot.Inventory.HideTimer < 0.25f)
                {
                    highlightedSubInventorySlots.Remove(subInventorySlot);
                }
            }

            if (character == Character.Controlled && character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
            {
                //remove the highlighted slots of other characters' inventories when not grabbing anyone
                highlightedSubInventorySlots.RemoveWhere(s => s.ParentInventory != this && s.ParentInventory?.Owner is Character);

                for (int i = 0; i < capacity; i++)
                {
                    var item = slots[i].FirstOrDefault();
                    if (item != null)
                    {
                        if (HideSlot(i)) { continue; }
                        if (character.HasEquippedItem(item)) // Keep a subinventory display open permanently when the container is equipped
                        {
                            var itemContainer = item.GetComponent<ItemContainer>();
                            if (itemContainer != null && 
                                itemContainer.KeepOpenWhenEquippedBy(character) && 
                                !DraggingItems.Contains(item) &&
                                character.CanAccessInventory(itemContainer.Inventory) &&
                                !highlightedSubInventorySlots.Any(s => s.Inventory == itemContainer.Inventory && s.SlotIndex == i))
                            {
                                ShowSubInventory(new SlotReference(this, visualSlots[i], i, false, itemContainer.Inventory), deltaTime, cam, hideSubInventories, true);
                            }
                        }
                    }
                }
            }

            if (doubleClickedItems.Any())
            {
                var quickUseAction = GetQuickUseAction(doubleClickedItems.First(), true, true, true);
                int itemCount = 0;
                foreach (Item doubleClickedItem in doubleClickedItems)
                {
                    QuickUseItem(doubleClickedItem, true, true, true, quickUseAction, playSound: doubleClickedItem == doubleClickedItems.First());
                    itemCount++;
                    //only use one item if we're equipping or using it as a treatment
                    if (quickUseAction == QuickUseAction.Equip || quickUseAction == QuickUseAction.UseTreatment)
                    {
                        break;
                    }
                    //if the item was put in a limb slot, only put one item from the stack
                    if (doubleClickedItem.ParentInventory == this && !IsInLimbSlot(doubleClickedItem, InvSlotType.Any))
                    {
                        break;
                    }
                    //if putting an item to a container with a max stack size of 1, only put one item from the stack
                    if (quickUseAction == QuickUseAction.PutToContainer && (character.SelectedItem?.GetComponent<ItemContainer>()?.MaxStackSize ?? 0) <= 1)
                    {
                        break;
                    }
                    if ((quickUseAction == QuickUseAction.TakeFromContainer || quickUseAction == QuickUseAction.PutToEquippedItem) &&
                        doubleClickedItem.ParentInventory != null &&
                        itemCount >= doubleClickedItem.Prefab.GetMaxStackSize(doubleClickedItem.ParentInventory))
                    {
                        break;
                    }
                }
            }

            for (int i = 0; i < capacity; i++)
            {
                var item = slots[i].FirstOrDefault();
                if (item != null)
                {
                    var slot = visualSlots[i];
                    if (item.AllowedSlots.Any(a => a != InvSlotType.Any && a != InvSlotType.HealthInterface))
                    {
                        HandleButtonEquipStates(item, slot, deltaTime);
                    }
                }
            }

            //cancel dragging if too far away from the container of the dragged item
            if (DraggingItems.Any())
            {
                var rootContainer = DraggingItems.First().RootContainer;
                var rootInventory = DraggingItems.First().ParentInventory;

                if (rootContainer != null)
                {
                    rootInventory = rootContainer.ParentInventory ?? rootContainer.GetComponent<ItemContainer>().Inventory;
                }

                if (rootInventory != null &&
                    rootInventory.Owner != Character.Controlled &&
                    rootInventory.Owner != Character.Controlled.SelectedItem &&
                    rootInventory.Owner != Character.Controlled.SelectedCharacter)
                {
                    //allow interacting if the container is linked to the item the character is interacting with
                    if (!(rootContainer != null && 
                        rootContainer.DisplaySideBySideWhenLinked && 
                        Character.Controlled.SelectedItem != null &&
                        rootContainer.linkedTo.Contains(Character.Controlled.SelectedItem)))
                    {
                        DraggingItems.Clear();
                    }
                }
            }
            doubleClickedItems.Clear();
        }

        public void UpdateSlotInput()
        {
            for (int i = 0; i < capacity; i++)
            {
                var firstItem = slots[i].FirstOrDefault();
                if (firstItem != null && !DraggingItems.Contains(firstItem) && Character.Controlled?.Inventory == this &&
                    GUI.KeyboardDispatcher.Subscriber == null && !CrewManager.IsCommandInterfaceOpen && PlayerInput.InventoryKeyHit(visualSlots[i].InventoryKeyIndex))
                {
                    if (SubEditorScreen.IsSubEditor() && SubEditorScreen.SkipInventorySlotUpdate) { continue; }
#if LINUX
                    // some window managers on Linux use windows key + number to change workspaces or perform other actions
                    if (PlayerInput.KeyDown(Keys.RightWindows) || PlayerInput.KeyDown(Keys.LeftWindows)) { continue; }
#endif
                    var quickUseAction = GetQuickUseAction(firstItem, true, false, true);
                    foreach (Item itemToUse in slots[i].Items.ToList())
                    {
                        QuickUseItem(itemToUse, true, true, true, quickUseAction, playSound: itemToUse == firstItem);
                        if (quickUseAction == QuickUseAction.Equip || quickUseAction == QuickUseAction.UseTreatment)
                        {
                            break;
                        }
                    }
                }
            }
        }

        private void HandleButtonEquipStates(Item item, VisualSlot slot, float deltaTime)
        {
            slot.EquipButtonState = slot.EquipButtonRect.Contains(PlayerInput.MousePosition) ?
                        GUIComponent.ComponentState.Hover : GUIComponent.ComponentState.None;
            if (PlayerInput.PrimaryMouseButtonHeld() && PlayerInput.SecondaryMouseButtonHeld())
            {
                slot.EquipButtonState = GUIComponent.ComponentState.None;
            }

            if (slot.EquipButtonState != GUIComponent.ComponentState.Hover)
            {
                slot.QuickUseTimer = Math.Max(0.0f, slot.QuickUseTimer - deltaTime * 5.0f);
                return;
            }

            var quickUseAction = GetQuickUseAction(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);

            if (quickUseAction != QuickUseAction.Drop)
            {
                slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
                    "" : TextManager.GetWithVariable("QuickUseAction." + quickUseAction.ToString(), "[equippeditem]", character.HeldItems.FirstOrDefault()?.Name ?? item?.Name);
                if (PlayerInput.PrimaryMouseButtonDown()) { slot.EquipButtonState = GUIComponent.ComponentState.Pressed; }
                if (PlayerInput.PrimaryMouseButtonClicked())
                {
                    QuickUseItem(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
                }
            }
        }

        private void ShowSubInventory(SlotReference slotRef, float deltaTime, Camera cam, List<SlotReference> hideSubInventories, bool isEquippedSubInventory)
        {
            Rectangle hoverArea = GetSubInventoryHoverArea(slotRef);
            if (isEquippedSubInventory && slotRef.Inventory is not ItemInventory { Container.MovableFrame: true, Container.KeepOpenWhenEquipped: true })
            {
                foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
                {
                    if (highlightedSubInventorySlot == slotRef) { continue; }
                    if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
                    {
                        return; // If an equipped one intersects with a currently active hover one, do not open
                    }
                }
            }

            if (isEquippedSubInventory)
            {
                slotRef.Inventory.OpenState = 1.0f; // Reset animation when initially equipped
            }

            highlightedSubInventorySlots.Add(slotRef);
            slotRef.Inventory.HideTimer = 1f;
            UpdateSubInventory(deltaTime, slotRef.SlotIndex, cam);

            //hide previously opened subinventories if this one overlaps with them
            foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
            {
                if (highlightedSubInventorySlot == slotRef) continue;
                if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
                {
                    hideSubInventories.Add(highlightedSubInventorySlot);
                    highlightedSubInventorySlot.Inventory.HideTimer = 0.0f;
                }
            }

            HintManager.OnShowSubInventory(slotRef?.Item);
        }
        
        public void AssignQuickUseNumKeys()
        {
            int keyBindIndex = 0;
            for (int i = 0; i < visualSlots.Length; i++)
            {
                if (HideSlot(i)) continue;
                if (SlotTypes[i] == InvSlotType.Any)
                {
                    visualSlots[i].InventoryKeyIndex = keyBindIndex;
                    keyBindIndex++;
                }
            }
        }

        private QuickUseAction GetQuickUseAction(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment)
        {
            if (!item.IsInteractable(Character.Controlled)) { return QuickUseAction.None; }

            if (allowApplyTreatment && CharacterHealth.OpenHealthWindow != null && 
                //if the item can be equipped in the health interface slot, don't use it as a treatment but try to equip it
                !item.AllowedSlots.Contains(InvSlotType.HealthInterface))
            {
                return QuickUseAction.UseTreatment;
            }
            
            if (item.ParentInventory != this)
            {
                if (Screen.Selected == GameMain.GameScreen)
                {
                    if (!item.IsInteractable(Character.Controlled))
                    {
                        return QuickUseAction.None;
                    }
                }
                if (item.ParentInventory == null || item.ParentInventory.Locked)
                {
                    return QuickUseAction.None;
                }
                //in another inventory -> attempt to place in the character's inventory
                else if (allowInventorySwap)
                {
                    if (item.Container == null || character.Inventory.FindIndex(item.Container) == -1) // Not a subinventory in the character's inventory
                    {
                        if (character.HeldItems.Any(i => i.OwnInventory != null && i.OwnInventory.CanBePut(item) && character.CanAccessInventory(i.OwnInventory)))
                        {
                            return QuickUseAction.PutToEquippedItem;
                        }
                        else
                        {
                            return item.ParentInventory is CharacterInventory ? QuickUseAction.TakeFromCharacter : QuickUseAction.TakeFromContainer;
                        }
                    }
                    else
                    {
                        var selectedContainer = character.SelectedItem?.GetComponent<ItemContainer>();
                        if (selectedContainer != null &&
                            selectedContainer.Inventory != null &&
                            !selectedContainer.Inventory.Locked)
                        {
                            // Move the item from the subinventory to the selected container
                            return QuickUseAction.PutToContainer;
                        }
                        else if (character.Inventory.AccessibleWhenAlive || character.Inventory.AccessibleByOwner)
                        {
                            // Take from the subinventory and place it in the character's main inventory if no target container is selected
                            return QuickUseAction.TakeFromContainer;
                        }
                    }
                }
            }
            else
            {
                var selectedContainer = character.SelectedItem?.GetComponent<ItemContainer>();

                if (selectedContainer != null && 
                    selectedContainer.Inventory != null && 
                    !selectedContainer.Inventory.Locked &&
                    selectedContainer.DrawInventory &&
                    allowInventorySwap)
                {
                    //player has selected the inventory of another item -> attempt to move the item there
                    return QuickUseAction.PutToContainer;
                }
                else if (character.SelectedCharacter?.Inventory != null && 
                    !character.SelectedCharacter.Inventory.Locked && 
                    allowInventorySwap)
                {
                    //player has selected the inventory of another character -> attempt to move the item there
                    return QuickUseAction.PutToCharacter;
                }
                else if (character.SelectedBy?.Inventory != null && 
                    Character.Controlled == character.SelectedBy &&
                    !character.SelectedBy.Inventory.Locked &&
                    (character.SelectedBy.Inventory.AccessibleWhenAlive || character.SelectedBy.Inventory.AccessibleByOwner) &&
                    allowInventorySwap)
                {
                    return QuickUseAction.TakeFromCharacter;
                }
                else if (character.HeldItems.FirstOrDefault(i =>
                    i.OwnInventory != null &&
                    i.OwnInventory.Container.DrawInventory &&
                    character.CanAccessInventory(i.OwnInventory) &&
                    (i.OwnInventory.CanBePut(item) || ((i.OwnInventory.Capacity == 1 || i.OwnInventory.Container.HasSubContainers) && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))) is { } equippedContainer)
                {
                    if (allowEquip)
                    {
                        if (!character.HasEquippedItem(item))
                        {
                            if (equippedContainer.GetComponent<ItemContainer>() is { QuickUseMovesItemsInside: false })
                            {
                                //put the item in a hand slot if that hand is free
                                if ((item.AllowedSlots.Contains(InvSlotType.RightHand) && character.Inventory.GetItemInLimbSlot(InvSlotType.RightHand) == null) ||
                                    (item.AllowedSlots.Contains(InvSlotType.LeftHand) && character.Inventory.GetItemInLimbSlot(InvSlotType.LeftHand) == null))
                                {
                                    return QuickUseAction.Equip;
                                }
                            }
                        }
                        //equipped -> attempt to unequip
                        else if (item.AllowedSlots.Contains(InvSlotType.Any))
                        {
                            return QuickUseAction.Unequip;
                        }
                    }
                    return QuickUseAction.PutToEquippedItem;
                }
                else if (allowEquip) //doubleclicked and no other inventory is selected
                {
                    //not equipped -> attempt to equip
                    if (!character.HasEquippedItem(item) || item.GetComponents<Pickable>().Count() > 1)
                    {
                        return QuickUseAction.Equip;
                    }
                    //equipped -> attempt to unequip
                    else if (item.AllowedSlots.Contains(InvSlotType.Any))
                    {
                        return QuickUseAction.Unequip;
                    }
                    else
                    {
                        return QuickUseAction.Drop;
                    }
                }
            }

            return QuickUseAction.None;
        }

        private void QuickUseItem(Item item, bool allowEquip, bool allowInventorySwap, bool allowApplyTreatment, QuickUseAction? action = null, bool playSound = true)
        {
            if (Screen.Selected is SubEditorScreen editor && !editor.WiringMode && !Submarine.Unloading)
            {
                // Find the slot the item was contained in and flash it
                if (item.ParentInventory?.visualSlots != null)
                {
                    var invSlots = item.ParentInventory.visualSlots;
                    for (int i = 0; i < invSlots.Length; i++)
                    {
                        if (i < 0 || invSlots.Length <= i || i < 0 || item.ParentInventory.Capacity <= i) { break; }
                        
                        var slot = invSlots[i];
                        if (item.ParentInventory.GetItemAt(i) == item)
                        {
                            slot.ShowBorderHighlight(GUIStyle.Red, 0.1f, 0.4f);
                            SoundPlayer.PlayUISound(GUISoundType.PickItem);
                            break;
                        }
                    }
                }
                
                SubEditorScreen.StoreCommand(new AddOrDeleteCommand(new List<MapEntity> { item }, true));

                item.Remove();
                return;
            }

            QuickUseAction quickUseAction = action ?? GetQuickUseAction(item, allowEquip, allowInventorySwap, allowApplyTreatment);
            bool success = false;
            switch (quickUseAction)
            {
                case QuickUseAction.Equip:
                    if (string.IsNullOrEmpty(item.Prefab.EquipConfirmationText) || character != Character.Controlled)
                    {
                        Equip();
                    }
                    else
                    {
                        if (GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "equipconfirmation")) { return; }
                        var equipConfirmation = new GUIMessageBox(string.Empty, TextManager.Get(item.Prefab.EquipConfirmationText),
                            new LocalizedString[] { TextManager.Get("yes"), TextManager.Get("no") })
                        {
                            UserData = "equipconfirmation"
                        };
                        equipConfirmation.Buttons[0].OnClicked = (btn, userdata) =>
                        {
                            Equip();
                            equipConfirmation.Close();
                            return true;
                        };
                        equipConfirmation.Buttons[1].OnClicked = equipConfirmation.Close;
                    }

                    void Equip()
                    {
                        //attempt to put in a free slot first
                        for (int i = capacity - 1; i >= 0; i--)
                        {
                            if (!slots[i].Empty()) { continue; }
                            if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
                            success = TryPutItem(item, i, true, false, Character.Controlled, true);
                            if (success) { break; }
                        }

                        if (!success)
                        {
                            for (int i = capacity - 1; i >= 0; i--)
                            {
                                if (SlotTypes[i] == InvSlotType.Any || !item.AllowedSlots.Any(a => a.HasFlag(SlotTypes[i]))) { continue; }
                                // something else already equipped in a hand slot, attempt to unequip it so items aren't unnecessarily swapped to it
                                if (!slots[i].Empty() && slots[i].First().AllowedSlots.Contains(InvSlotType.Any) && 
                                    (SlotTypes[i] == InvSlotType.LeftHand || SlotTypes[i] == InvSlotType.RightHand))
                                {
                                    TryPutItem(slots[i].First(), Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
                                }
                                success = TryPutItem(item, i, true, false, Character.Controlled, true);
                                if (success) { break; }
                            }
                        }
                    }
                    break;
                case QuickUseAction.Unequip:
                    if (item.AllowedSlots.Contains(InvSlotType.Any))
                    {
                        success = TryPutItem(item, Character.Controlled, new List<InvSlotType>() { InvSlotType.Any }, true);
                    }
                    break;
                case QuickUseAction.UseTreatment:
                    CharacterHealth.OpenHealthWindow?.OnItemDropped(item, ignoreMousePos: true);
                    return;
                case QuickUseAction.Drop:
                    //do nothing, the item is dropped after a delay
                    return;
                case QuickUseAction.PutToCharacter:
                    if (character.SelectedCharacter != null && character.SelectedCharacter.Inventory != null)
                    {
                        //player has selected the inventory of another character -> attempt to move the item there
                        success = character.SelectedCharacter.Inventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
                    }
                    break;
                case QuickUseAction.PutToContainer:
                    var selectedContainer = character.SelectedItem?.GetComponent<ItemContainer>();
                    if (selectedContainer != null && selectedContainer.Inventory != null)
                    {
                        //player has selected the inventory of another item -> attempt to move the item there
                        success = selectedContainer.Inventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
                    }
                    break;
                case QuickUseAction.TakeFromCharacter:
                    if (character.SelectedBy != null && Character.Controlled == character.SelectedBy &&
                        character.SelectedBy.Inventory != null)
                    {
                        //item is in the inventory of another character -> attempt to get the item from there
                        success = character.SelectedBy.Inventory.TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
                    }
                    break;
                case QuickUseAction.TakeFromContainer:
                    // Check open subinventories and put the item in it if equipped
                    ItemInventory activeSubInventory = null;
                    for (int i = 0; i < capacity; i++)
                    {
                        activeSubInventory = GetActiveEquippedSubInventory(i);
                        if (activeSubInventory != null)
                        {
                            success = activeSubInventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
                            break;
                        }
                    }                            

                    // No subinventory found or placing unsuccessful -> attempt to put in the character's inventory
                    if (!success)
                    {
                        success = TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
                    }
                    break;
                case QuickUseAction.PutToEquippedItem:
                    //order by the condition of the contained item to prefer putting into the item with the emptiest ammo/battery/tank
                    foreach (Item heldItem in character.HeldItems.OrderByDescending(heldItem => GetContainPriority(item, heldItem)))
                    {
                        if (heldItem.OwnInventory == null || !heldItem.OwnInventory.Container.DrawInventory) { continue; }
                        //don't allow swapping if we're moving items into an item with 1 slot holding a stack of items
                        //(in that case, the quick action should just fill up the stack)
                        bool disallowSwapping = 
                            (heldItem.OwnInventory.Capacity == 1 || heldItem.OwnInventory.Container.HasSubContainers) &&
                            heldItem.OwnInventory.GetItemAt(0)?.Prefab == item.Prefab && 
                            heldItem.OwnInventory.GetItemsAt(0).Count() > 1;
                        if (heldItem.OwnInventory.TryPutItem(item, Character.Controlled) || 
                            ((heldItem.OwnInventory.Capacity == 1 || heldItem.OwnInventory.Container.HasSubContainers) && heldItem.OwnInventory.TryPutItem(item, 0, allowSwapping: !disallowSwapping, allowCombine: false, user: Character.Controlled)))
                        {
                            success = true;
                            for (int j = 0; j < capacity; j++)
                            {
                                if (slots[j].Contains(heldItem)) { visualSlots[j].ShowBorderHighlight(GUIStyle.Green, 0.1f, 0.4f); }
                            }
                            break;
                        }
                    }
                    break;

                    static float GetContainPriority(Item item, Item containerItem)
                    {
                        var container = containerItem.GetComponent<ItemContainer>();
                        if (container == null) { return 0.0f; }
                        for (int i = 0; i < container.Inventory.Capacity; i++)
                        {
                            var containedItems = container.Inventory.GetItemsAt(i);
                            if (containedItems.Any() && container.Inventory.CanBePutInSlot(item, i))
                            {
                                //if there's a stack in the contained item that we can add the item to, prefer that
                                return 10.0f;
                            }
                        }
                        return -container.GetContainedIndicatorState();
                    }
            }

            if (success)
            {
                for (int i = 0; i < capacity; i++)
                {
                    if (slots[i].Contains(item)) { visualSlots[i].ShowBorderHighlight(GUIStyle.Green, 0.1f, 0.4f); }
                }
            }

            DraggingItems.Clear();
            if (playSound)
            {
                SoundPlayer.PlayUISound(success ? GUISoundType.PickItem : GUISoundType.PickItemFail);
            }
        }

        public bool CanBeAutoMovedToCorrectSlots(Item item)
        {
            if (item == null) { return false; }
            foreach (var allowedSlot in item.AllowedSlots)
            {
                InvSlotType slotsFree = InvSlotType.None;
                for (int i = 0; i < slots.Length; i++)
                {
                    if (allowedSlot.HasFlag(SlotTypes[i]) && slots[i].Empty()) { slotsFree |= SlotTypes[i]; }
                }
                if (allowedSlot == slotsFree) { return true; }
            }
            return false;
        }

        /// <summary>
        /// Flash the slots the item is allowed to go in (not taking into account whether there's already something in those slots)
        /// </summary>
        public void FlashAllowedSlots(Item item, Color color)
        {
            if (item == null || visualSlots == null) { return; }
            bool flashed = false;
            foreach (var allowedSlot in item.AllowedSlots)
            {
                for (int i = 0; i < slots.Length; i++)
                {
                    if (allowedSlot.HasFlag(SlotTypes[i]))
                    {
                        visualSlots[i].ShowBorderHighlight(color, 0.1f, 0.9f);
                        flashed = true;
                    }
                }
            }
            if (flashed)
            {
                SoundPlayer.PlayUISound(GUISoundType.PickItemFail);
            }
        }


        public void DrawOwn(SpriteBatch spriteBatch)
        {
            if (!AccessibleWhenAlive && !character.IsDead && !AccessibleByOwner) { return; }
            if (capacity == 0) { return; }
            if (visualSlots == null) { CreateSlots(); }
            if (GameMain.GraphicsWidth != screenResolution.X ||
                GameMain.GraphicsHeight != screenResolution.Y ||
                prevUIScale != UIScale ||
                prevHUDScale != GUI.Scale)
            {
                CreateSlots();
                SetSlotPositions(layout);
                prevUIScale = UIScale;
                prevHUDScale = GUI.Scale;
            }

            if (layout == Layout.Center)
            {
                CalculateBackgroundFrame();
                GUI.DrawRectangle(spriteBatch, BackgroundFrame, Color.Black * 0.8f, true);
                GUI.DrawString(spriteBatch,
                    new Vector2((int)(BackgroundFrame.Center.X - GUIStyle.Font.MeasureString(character.Name).X / 2), (int)BackgroundFrame.Y + 5),
                    character.Name, Color.White * 0.9f);
            }

            for (int i = 0; i < capacity; i++)
            {
                if (HideSlot(i) || SlotTypes[i] == InvSlotType.HealthInterface) { continue; }

                //don't draw the item if it's being dragged out of the slot
                bool drawItem = !DraggingItems.Any() || !slots[i].Items.All(it => DraggingItems.Contains(it)) || visualSlots[i].MouseOn();

                DrawSlot(spriteBatch, this, visualSlots[i], slots[i].FirstOrDefault(), i, drawItem, SlotTypes[i]);
            }
            
            VisualSlot highlightedQuickUseSlot = null;
            Rectangle inventoryArea = Rectangle.Empty;

            for (int i = 0; i < capacity; i++)
            {
                if (HideSlot(i)) { continue; }

                inventoryArea = inventoryArea == Rectangle.Empty ? visualSlots[i].InteractRect : Rectangle.Union(inventoryArea, visualSlots[i].InteractRect);

                if (slots[i].Empty() || 
                    (DraggingItems.Any(it => slots[i].Contains(it)) && !visualSlots[i].InteractRect.Contains(PlayerInput.MousePosition)) || 
                    !slots[i].First().AllowedSlots.Any(a => a != InvSlotType.Any))
                {
                    //draw limb icons on empty slots
                    if (LimbSlotIcons.ContainsKey(SlotTypes[i]))
                    {
                        var icon = LimbSlotIcons[SlotTypes[i]];
                        icon.Draw(spriteBatch, visualSlots[i].Rect.Center.ToVector2() + visualSlots[i].DrawOffset, GUIStyle.EquipmentSlotIconColor, origin: icon.size / 2, scale: visualSlots[i].Rect.Width / icon.size.X);
                    }
                    continue;
                }
                if (DraggingItems.Any(it => slots[i].Contains(it)) && !visualSlots[i].IsHighlighted) { continue; }
                
                //draw hand icons if the item is equipped in a hand slot
                if (IsInLimbSlot(slots[i].First(), InvSlotType.LeftHand))
                {
                    var icon = LimbSlotIcons[InvSlotType.LeftHand];
                    icon.Draw(spriteBatch, new Vector2(visualSlots[i].Rect.X, visualSlots[i].Rect.Bottom) + visualSlots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.35f, icon.size.Y * 0.75f), scale: visualSlots[i].Rect.Width / icon.size.X * 0.7f);
                }
                if (IsInLimbSlot(slots[i].First(), InvSlotType.RightHand))
                {
                    var icon = LimbSlotIcons[InvSlotType.RightHand];
                    icon.Draw(spriteBatch, new Vector2(visualSlots[i].Rect.Right, visualSlots[i].Rect.Bottom) + visualSlots[i].DrawOffset, Color.White * 0.6f, origin: new Vector2(icon.size.X * 0.65f, icon.size.Y * 0.75f), scale: visualSlots[i].Rect.Width / icon.size.X * 0.7f);
                }

                GUIComponent.ComponentState state = visualSlots[i].EquipButtonState;
                if (state == GUIComponent.ComponentState.Hover)
                {       
                    highlightedQuickUseSlot = visualSlots[i];
                }

                if (slots[i].First().AllowedSlots.Count() == 1 || SlotTypes[i] == InvSlotType.HealthInterface)
                {
                    continue;
                }

                Color color = Color.White;
                if (Locked)
                { 
                    color *= 0.5f; 
                }

                Vector2 indicatorScale = new Vector2(
                     visualSlots[i].EquipButtonRect.Size.X / EquippedIndicator.size.X,
                    visualSlots[i].EquipButtonRect.Size.Y / EquippedIndicator.size.Y);

                bool isEquipped = character.HasEquippedItem(slots[i].First());
                var sprite = state switch
                {
                    GUIComponent.ComponentState.None
                        => isEquipped ? EquippedIndicator : UnequippedIndicator,
                    GUIComponent.ComponentState.Hover
                        => isEquipped ? EquippedHoverIndicator : UnequippedHoverIndicator,
                    GUIComponent.ComponentState.Pressed
                    or GUIComponent.ComponentState.Selected
                    or GUIComponent.ComponentState.HoverSelected
                        => isEquipped ? EquippedClickedIndicator : UnequippedClickedIndicator,
                    _ => throw new NotImplementedException()
                };
                sprite.Draw(spriteBatch, visualSlots[i].EquipButtonRect.Center.ToVector2(), color, EquippedIndicator.Origin, 0, indicatorScale);
            }

            if (Locked)
            {
                GUI.DrawRectangle(spriteBatch, inventoryArea, new Color(30,30,30,100), isFilled: true);
                var lockIcon = GUIStyle.GetComponentStyle("LockIcon")?.GetDefaultSprite();
                lockIcon?.Draw(spriteBatch, inventoryArea.Center.ToVector2(), scale: Math.Min(inventoryArea.Height / lockIcon.size.Y * 0.7f, 1.0f));
                if (inventoryArea.Contains(PlayerInput.MousePosition) && character.LockHands)
                {
                    GUIComponent.DrawToolTip(spriteBatch, TextManager.Get("handcuffed"), new Rectangle(inventoryArea.Center - new Point(inventoryArea.Height / 2), new Point(inventoryArea.Height)));
                }
            }
            else if (highlightedQuickUseSlot != null && !highlightedQuickUseSlot.QuickUseButtonToolTip.IsNullOrEmpty())
            {
                GUIComponent.DrawToolTip(spriteBatch, highlightedQuickUseSlot.QuickUseButtonToolTip, highlightedQuickUseSlot.EquipButtonRect);
            }
        }

        public void ClientEventWrite(IWriteMessage msg, Character.InventoryStateEventData extraData)
        {
            SharedWrite(msg, extraData.SlotRange);
            syncItemsDelay = 1.0f;
        }
    }
}
