using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using System; using static SimpleInventorySystem.GridUI; namespace SimpleInventorySystem { public class SlotUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { [Header("Slot Attributes")] public int width; public int height; public Image image; public bool useImageAsSlotHolder; public bool EquipSlot; public bool FitItemImageInSlotImage = false; [Header("Slot-to-Item Compatibility")] public bool IgnoreItemSize; public List AllowedItemTags; public List DisallowedItemTags; public List HasSlotsBelongingToItem; // Hidden In Inspector [HideInInspector] public Stack stackedItems = new Stack(); // WARNING: Stack can give some odd troubles with the raycast, consider revision or consideration. [HideInInspector] public LimitStackSlot limitStackSlot; [HideInInspector] public LimitStackSlotManager limitStackSlotManager; [HideInInspector] public bool DroppedOnFrame; [HideInInspector] public List LinkedSlots = new List(); [HideInInspector] public List groupSlots; [HideInInspector] public GridUI grid; [HideInInspector] public GridUI.Cell cell; [HideInInspector] public bool CellInUse; [HideInInspector] public float imageScale = 1f; // TODO: See if this is still necessary [HideInInspector] public bool StackItemsOnSlot; // TODO: Figure out if this should be kept hidden // private variables [SerializeField] private ItemUI itemUI { get { if (stackedItems.Count == 0) { return null; } Debug.Log("Peek: " + stackedItems.Peek().gameObject.name); return stackedItems.Peek(); } } private AppendUI appendUI; private LinkedSlotUI linkedSlotUI; private bool droppedStackOntoEmptySlot; private RenderItemUIProperty renderProp; private SlotUI BelongsToItemInSlot; // public variables public bool PointerIsHoveredOver { get { return InventorySystem.IsMouseOverUI(gameObject); } } public ItemUI GetItemUI() { return itemUI; } /*public void OnDrop(PointerEventData eventData) { // //("OnDrop"); if (eventData.pointerDrag != null && AllowedDraggable(eventData.pointerDrag)) { DropOntoSlot(eventData.pointerDrag); } }*/ public bool AllowedDraggable(GameObject gameObject) { return gameObject.GetComponent() != null; } public bool IsLinkedSlot() { return linkedSlotUI != null; } public bool DropOntoSlot(GameObject item, bool dropStack = true) { ItemUI itemDrop = item.GetComponent(); ItemTags itemTag = itemDrop.ItemTag; bool allowed = AllowedItemTags == null || AllowedItemTags.Count == 0 || AllowedItemTags.Contains(ItemTags.Any) || AllowedItemTags.Contains(itemTag); bool disallowed = DisallowedItemTags.Contains(itemTag); if (!allowed || disallowed) { return false; } if (itemDrop.Stackable && StackItemsOnSlot) { Debug.LogWarning("Item stacks are incompattible with slot stacking."); return false; } if (limitStackSlot != null && limitStackSlot.HasReachedLimit()) { return false; } if (IsLinkedSlot()) { /*GameObject newItemDrop = Instantiate(item); itemDrop = newItemDrop.GetComponent(); itemDrop.IsLinkedSlotClone = true;*/ } List occupiedCells = new List(); /// STACKING /// This section concerns item stacks, not slot stacking if (!itemDrop.IsLinkedSlotClone && ((HasStack() && itemUI != null /*&& itemUI.itemPrefab == itemDrop.itemPrefab*/) || !dropStack)) { Debug.Log("Handling Stack"); int maxStackDrop = 1; if (dropStack) { maxStackDrop = itemDrop.Count; if (maxStackDrop > itemUI.StackLimit - itemUI.Count) { maxStackDrop = itemDrop.Count - itemUI.Count; } } if (itemUI != null) { if (itemUI.AddToStack(maxStackDrop)) { Debug.Log("Add to stack"); itemDrop.RemoveFromStack(maxStackDrop); if (appendUI != null && appendUI.StackAppend) { appendUI.AppendUIToTransform(itemDrop); } return true; } } else { Debug.Log("Stack handling"); GameObject GO = Instantiate(item, transform, false); GO.transform.localPosition = new Vector3(0, 0, 0); ItemUI oldItemDrop = itemDrop; itemDrop = GO.GetComponent(); if (itemDrop.AddToStack(maxStackDrop)) { oldItemDrop.RemoveFromStack(maxStackDrop); } else { return false; } } } bool dropCheck = (grid != null && grid.CanMoveInCells(itemDrop, this, occupiedCells)) || (grid == null && !cell.inUse && (IgnoreItemSize || (cell.slot.width >= itemDrop.SizeAfterOrientation().Width && !cell.inUse && cell.slot.height >= itemDrop.SizeAfterOrientation().Height))); Debug.Log("DropCheck" + (grid == null && !cell.inUse && (IgnoreItemSize || (cell.slot.width >= itemDrop.SizeAfterOrientation().Width && !cell.inUse && cell.slot.height >= itemDrop.SizeAfterOrientation().Height)))); /*Debug.Log("GridUI: DropOntoSlot(): " + gameObject.name + ": " + "dropCheck: " + dropCheck); Debug.Log("GridUI: DropOntoSlot(): " + gameObject.name + ": " + "allowed: " + allowed);*/ if (dropCheck) { if ((occupiedCells != null && occupiedCells.Count > 1) || StackItemsOnSlot) { //Debug.Log("SlotUI: " + occupiedCells.Count); itemDrop.SetSlots(occupiedCells); } else { Debug.Log("In Use"); cell.inUse = true; CellInUse = cell.inUse; } Transform parent = transform; if (useImageAsSlotHolder && image != null) { parent = image.gameObject.transform; } item.GetComponent().SetParent(parent); item.GetComponent().anchoredPosition = GetComponent().anchoredPosition; //item.GetComponent().pivot = new Vector2(0, 1); if(FitItemImageInSlotImage) itemDrop.FitImageInSlot(image.GetComponent().sizeDelta); itemDrop.SetSlot(this); stackedItems.Push(itemDrop); Debug.Log("SlotUI:Drop:" + itemUI + ", " + itemDrop); itemUI.DropItemOntoSlot(); if (itemUI.Stackable) { droppedStackOntoEmptySlot = true; } if (!IsLinkedSlot()) { foreach (SlotUI ls in LinkedSlots) { if (ls == this) { Debug.LogWarning("No self-referencing for this array ;)"); continue; } //ls.DropOntoSlot(item); } } if (grid != null) { grid.HideSlotsOfItem(itemDrop); } if (!useImageAsSlotHolder) { HideImage(); } foreach (GroupSlotUI groupSlot in groupSlots) { if (groupSlot != null) { groupSlot.OnItemDropped(); } } if (appendUI != null) { Debug.Log("Test"); appendUI.AppendUIToTransform(itemUI); } if (limitStackSlotManager != null) { limitStackSlotManager.SetStackSlotLimit(itemUI); } if (limitStackSlot != null) { limitStackSlot.Increment(); } if (BelongsToItemInSlot != null && BelongsToItemInSlot.GetItemUI() != null) { BelongsToItemInSlot.GetItemUI().AddToContainedItems(itemUI); } if (HasSlotsBelongingToItem != null) { foreach (ItemUI i in itemUI.ContainedItems) { foreach(SlotUI s in HasSlotsBelongingToItem) { if (s.AllowedItemTags.Contains(i.ItemTag)) { s.AddContainedItemToSlot(i); break; } } } } SetRenderItemUIPropertyValue(); return true; } else if (itemDrop.previousSlot != this) { // TODO: See why this is outputting at beginning, probably from test objects in Loot //Debug.LogWarning("SlotUI: Failed to drop. dropCheck: " + dropCheck + ", allowed: " + allowed); // return item to previous parent itemDrop.ReturnToSlot(); return false; //Debug.Log("Resetting parent"); } else { //Debug.LogWarning("SlotUI: Failed to drop. dropCheck: " + dropCheck + ", allowed: " + allowed); Debug.LogError("SlotUI: Something wrong has happened."); return false; } } void Awake() { if (image == null) { Image[] images = GetComponentsInChildren(); // This will retrieve the first instance of an image in the FIRST child with the component //Debug.Log(images.Length); if (images.Length > 0) { if (images[0].transform == transform) { if (images.Length > 1) { image = images[1]; } } else { image = images[0]; } } } if (grid == null) grid = GetComponentInParent(); // Check again if (grid == null) { cell = new Cell(0, 0, this, true); } if (TryGetComponent(out AppendUI aui)) { appendUI = aui; } if (TryGetComponent(out LinkedSlotUI lui)) { linkedSlotUI = lui; } if (TryGetComponent(out RenderItemUIProperty rp)) { renderProp = GetComponent(); SetRenderItemUIPropertyValue(); } if (TryGetComponent(out LimitStackSlot lss)) { limitStackSlot = lss; } if (TryGetComponent(out LimitStackSlotManager lssm)) { limitStackSlotManager = lssm; } } private void SetRenderItemUIPropertyValue() { if (renderProp != null) { renderProp.value = stackedItems.Count.ToString(); } } public void AddContainedItemToSlot(ItemUI item) { HideImage(); if (limitStackSlot != null) { limitStackSlot.Increment(); } stackedItems.Push(item); item.transform.SetParent(transform, false); item.gameObject.SetActive(true); /* foreach(ItemUI item in ) { itemUI.transform.SetParent(itemUI.ParentContainer.transform, false); itemUI.gameObject.SetActive(false); stackedItems.Pop(); }*/ SetRenderItemUIPropertyValue(); } public void RemoveContainedItemsFromSlot() { ShowImage(); while (stackedItems.Count > 0) { if (limitStackSlot != null) { limitStackSlot.Decrement(); } if (itemUI.ParentContainer == null) { Debug.LogWarning("This should not be null"); } if (itemUI.ParentContainer != null) itemUI.transform.SetParent(itemUI.ParentContainer.transform, false); itemUI.gameObject.SetActive(false); ItemUI oldItem = stackedItems.Pop(); oldItem.SetSlot(this); } SetRenderItemUIPropertyValue(); } public void RemoveDragDropItem() { if (BelongsToItemInSlot != null && BelongsToItemInSlot.GetItemUI() != null) { BelongsToItemInSlot.GetItemUI().RemoveFromContainedItems(itemUI); } if (HasSlotsBelongingToItem != null) { foreach (SlotUI s in HasSlotsBelongingToItem) { s.RemoveContainedItemsFromSlot(); } } if (appendUI != null) { appendUI.RemoveUIFromTransform(itemUI); } if (limitStackSlot != null) { limitStackSlot.Decrement(); } if (limitStackSlotManager != null) { limitStackSlotManager.UnsetStackSlotLimit(); } foreach (SlotUI linked in LinkedSlots) { linked.RemoveDragDropItem(); } stackedItems.Pop(); foreach (GroupSlotUI groupSlot in groupSlots) { groupSlot.OnItemRemoved(); } UnsetCell(); SetRenderItemUIPropertyValue(); } public void UnsetCell() { if(itemUI == null) { ShowImage(); if (cell != null) { cell.inUse = false; CellInUse = cell.inUse; } } } public bool IsSingleCellSlot() { return width == 1 && height == 1; } public bool HasStack() { return itemUI != null && itemUI.Stackable; } public bool IsStacking() { return StackItemsOnSlot; } // Start is called before the first frame update void Start() { if (HasSlotsBelongingToItem.Count > 0) { foreach (SlotUI s in HasSlotsBelongingToItem) { s.BelongsToItemInSlot = this; } } else { HasSlotsBelongingToItem = null; } } // Update is called once per frame void Update() { if (InventorySystem.instance.PressedDropItemKey(false) || InventorySystem.instance.PressedEquipItemKey(false)) { return; } if (PointerIsHoveredOver) { ItemUI droppedItem = InventorySystem.instance.DraggedItem; if (droppedItem != null && !droppedItem.PickedUpOnFrame) { if (Input.GetMouseButtonDown(0)) { DroppedOnFrame = true; bool callback = DropOntoSlot(droppedItem.gameObject, true); if (callback && droppedItem.Stackable) { if (droppedItem.Count <= 0) { Destroy(droppedItem.gameObject); } else if (itemUI.Count < droppedItem.Count && !droppedStackOntoEmptySlot) { InventorySystem.instance.DraggedItem = droppedItem; droppedStackOntoEmptySlot = false; } } } else if (Input.GetMouseButtonDown(1) && droppedItem.Stackable) { DroppedOnFrame = true; Debug.Log("Right Click"); if (DropOntoSlot(droppedItem.gameObject, false)) { if (droppedItem.Count <= 0) { Destroy(droppedItem.gameObject); } else { InventorySystem.instance.DraggedItem = droppedItem; droppedItem.transform.SetParent(InventorySystem.instance.inventoryUI.transform); droppedStackOntoEmptySlot = false; } } } } } // TODO: make sure the key combo works as expected if (Input.GetMouseButtonUp(0)) { DroppedOnFrame = false; } } public void SetCell(Cell cell) { this.cell = cell; } internal void HideImage() { if (image != null) { image.color = new Color(image.color.r, image.color.g, image.color.b, 0); //image.color = new Color(image.color.r, image.color.g, image.color.b, 1); } } internal void ShowImage() { if (image != null) { //image.color = new Color(image.color.r, image.color.g, image.color.b, 0); image.color = new Color(image.color.r, image.color.g, image.color.b, 1); } } public void OnPointerClick(PointerEventData eventData) { } public void OnPointerDown(PointerEventData eventData) { if(InventorySystem.instance.PressedDropItemKey(false) || InventorySystem.instance.PressedEquipItemKey(false)) { return; } ItemUI droppedItem = InventorySystem.instance.DraggedItem; if (droppedItem != null && !droppedItem.PickedUpOnFrame) { DropOntoSlot(droppedItem.gameObject); } } public void OnPointerExit(PointerEventData eventData) { //PointerIsHoveredOver = false; } public void OnPointerEnter(PointerEventData eventData) { //PointerIsHoveredOver = true; } } }