using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems; using static SimpleInventorySystem.GridUI; using System; using TMPro; namespace SimpleInventorySystem { [RequireComponent(typeof(RectTransform), typeof(CanvasGroup))] public class ItemUI : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler { [Header("Item Attributes")] public string itemName; public string displayName; public Image image; public RarityType rarity; public ItemTags ItemTag = ItemTags.Any; public int StackLimit = 1; public int width; public int height; public float weight; public float monetaryValue; [Header("Container Prefab")] public GameObject containerUIPrefab; [Header("Required Component Links")] public Image backdropImage; public RectTransform emptyGridContainer; public TextMeshProUGUI titleText; public TextMeshProUGUI stackText; // Hidden public variables [HideInInspector] public bool interactable = true; [HideInInspector] public Canvas overrideSortingCanvas; [HideInInspector] public bool Equipped; [HideInInspector] public List ContainedItems = new List(); [HideInInspector] public ItemUI ParentContainer; [HideInInspector] public GameObject container; [HideInInspector] public Canvas canvas; [HideInInspector] public bool PickedUpOnFrame; [HideInInspector] public List ContextWindows = new List(); [HideInInspector] public StorageWindowUI StorageWindow; [HideInInspector] public LimitStackSlotCapacity limitStackSlotCapacity; internal void ResetTransform() { RectTransform rect = GetComponent(); rect.anchorMin = rect.anchorMax = rect.pivot = new Vector2(0, 1); rect.anchoredPosition = new Vector2(); imageSizeOnGrid = new Size(width * InventorySystem.instance.DefaultSizeOnGrid.Width, height * InventorySystem.instance.DefaultSizeOnGrid.Height); rect.sizeDelta = new Vector2(imageSizeOnGrid.Width, imageSizeOnGrid.Height); } [HideInInspector] public PickUp pickUp; [HideInInspector] public TargetAttachment targetAttachment; // private variables private Vector2 oldImageSizeDelta; private Vector2 oldSizeDelta; private RectTransform rectTransform; private CanvasGroup canvasGroup; private float scale = 1f; private SlotUI slot; private Cell[] cells; private bool isDragging; private Size imageSizeOnGrid; private Orientation imageOrientation = Orientation.Portrait; [HideInInspector] public Inventory Inventory; // archived variables //public Item itemPrefab; //public variables public SlotUI previousSlot { get; private set; } public bool Stackable { get { return StackLimit > 1; } } private int count; public int Count { get { return count; } set { if (!Stackable) { count = 1; } else { count = value; } SetRenderItemUIPropertyValue(); } } public bool PointerIsHoveredOver { get { return InventorySystem.IsMouseOverItemUITop(this); } } //public Item item; private void Awake() { rectTransform = GetComponent(); if (image == null) { Image[] images = transform.GetComponentsInChildren(); for (int i = 0; i < images.Length; i++) { if (images[i] == GetComponent()) { continue; } image = transform.GetComponentInChildren(); break; } } if (image == null) { Debug.LogError("ItemUI: Item needs a child with an Image component."); } canvasGroup = GetComponent(); limitStackSlotCapacity = GetComponent(); if (width <= 0 || height <= 0) { Debug.LogError("Inventory ItemUI must contain a positive integer value for Width and Height: " + name); } int eulerAngle = Mathf.Abs(Mathf.CeilToInt(transform.rotation.eulerAngles.z)); switch (eulerAngle) { case 270: imageOrientation = (height > width) ? Orientation.Portrait : Orientation.Landscape; break; case 180: imageOrientation = (width > height) ? Orientation.Landscape : Orientation.Portrait; break; case 90: imageOrientation = (height > width) ? Orientation.Portrait : Orientation.Landscape; break; default: imageOrientation = (width > height) ? Orientation.Landscape : Orientation.Portrait; break; } //InstantiateItem(); } public Rarity GetRarity() { //Debug.Log(rarity); return InventorySystem.instance.GetRarityFromList(rarity); } /// /// Returns an integer number if it has a container with a GridUI. the number returned is either -1 if no gridUI exists, or the capacity in terms of 1x1 cells. /// /// public int ContainerCapacity() { GridUI gridUI = null; if (container != null && container.TryGetComponent(out gridUI)) { return gridUI.gridSize.Width * gridUI.gridSize.Height; } return -1; } public void FindTextMeshProUGUI() { if(titleText == null) { Transform titleGameObject = transform.Find("Title"); if(titleGameObject != null) { titleText = titleGameObject.GetComponent(); } } if (stackText == null) { Transform stackTextGameObject = transform.Find("StackCount"); if (stackTextGameObject != null) { stackText = stackTextGameObject.GetComponent(); } } } private void SetRenderItemUIPropertyValue() { if (titleText != null) { Debug.Log($"Set Item name: {itemName}"); titleText.text = (displayName != null && !string.IsNullOrEmpty(displayName)) ? displayName : itemName; } if(stackText != null) { stackText.text = Count.ToString(); } } public void InstantiateItem() { //if (item == null && itemPrefab != null) //{ // item = Instantiate(itemPrefab); //} } public SlotUI GetSlotUI() { return slot; } public void OnEndDrag(PointerEventData eventData) { //rectTransform.localPosition = new Vector3(0, 0); } public bool QuickMove() { bool moved = false; if (Equip()) { //Debug.Log("Equipped"); moved = true; } else if (Store()) { //Debug.Log("Stored"); moved = true; } return moved; } public bool Equip() { bool equipped = false; foreach (TagSlotPairing tsp in InventorySystem.instance.TagSlotPairings) { //Debug.Log($"Equip: {tsp.itemTag}, {tsp.slot.gameObject.name}"); if (tsp.slot == slot) { //Debug.Log("Could not equip, storing"); continue; } if (tsp.CanEquip(this)) { UnsetSlot(); equipped = tsp.DropOntoSlot(this); //Debug.Log(tsp.slot.gameObject.name); if (equipped) { break; } else { //Debug.Log("Returning to slot"); ReturnToSlot(); } } } return equipped; } public bool Store() { bool stored = false; foreach (TagSlotGridPairing tsgp in InventorySystem.instance.TagSlotGridPairings) { //Debug.Log($"Store: {tsgp.itemTag}, {tsgp.ReferencedGrid}"); if (tsgp.CanStore(this)) { GrabAndDragItem(); // TODO: See if this conflicts with anything //UnsetSlot(); stored = tsgp.Drop(this); if (!stored) { ReturnToSlot(); } else { // TODO: see if this is needed if(container != null) container.SetActive(false); break; } } } return stored; } public bool DropItemInStorageContainer(ItemUI droppedItem) { //Debug.Log("Checking"); if (IsStorageContainer()) { //Debug.Log("Storage container found"); return container.GetComponent().DropItemOnGrid(droppedItem.gameObject); } return false; } public void DropItemOntoSlot(bool fitImageInSlot = false) { //Debug.Log("OnEndDrag"); if (image != null) { canvasGroup.alpha = 1f; image.maskable = true; } canvasGroup.blocksRaycasts = true; isDragging = false; if (!slot.useImageAsSlotHolder) ShowEmptyGrid(); else HideEmptyGrid(); InventorySystem.instance.DraggedItem = null; if (slot == null) { //Debug.Log("ItemUI: OnEndDrag: Returning to parent"); //ReturnToSlot(); } else { // TODO: this need improvement Equipped = slot.EquipSlot; } if (StorageWindow != null && StorageWindow.gameObject.activeSelf) { StorageWindow.dragWindowUI.CloseWindow(); } if (Inventory == null) { InventorySystem.instance.player.inventory.AddOwnership(this, null); } else if (Inventory != InventorySystem.instance.player.inventory) { Inventory.RemoveOwnership(this, Inventory); } if (!fitImageInSlot) { ApplyRectTransformResize(); transform.localRotation = Quaternion.Euler(0, 0, 0); // TODO: Fix this so it maintains rotation later } } public void ApplyRectTransformResize() { ResetTransform(); } public void GrabAndDragItem() { if (!isDragging && interactable) { //Debug.Log("GRAB AND DRAG"); //Debug.Log("OnPointerDown"); //Debug.Log("OnBeginDrag"); RemoveItemFromSlot(); isDragging = true; InventorySystem.instance.DraggedItem = this; PickedUpOnFrame = true; } } public void RemoveItemFromSlot() { canvasGroup.alpha = .7f; canvasGroup.blocksRaycasts = false; transform.SetParent(canvas.transform); rectTransform.anchorMin = new Vector2(0, 1); rectTransform.anchorMax = new Vector2(0, 1); rectTransform.pivot = new Vector2(0, 1); image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, oldImageSizeDelta.x); image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, oldImageSizeDelta.y); rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, oldSizeDelta.x); rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, oldSizeDelta.y); emptyGridContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, oldSizeDelta.x); emptyGridContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, oldSizeDelta.y); backdropImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, oldSizeDelta.x); backdropImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, oldSizeDelta.y); UnsetSlot(); HideEmptyGrid(); // Destroy each associated window, since we won't rely on windows if we are moving this item for (int i = ContextWindows.Count - 1; i >= 0; i--) { ContextWindows[i].SetActive(true); } ContextWindows.Clear(); } public void UnsetSlot() { if (slot != null) { if(slot.grid != null) { slot.grid.RemoveItemFromGrid(this); } previousSlot = slot; slot.RemoveDragDropItem(); slot = null; } if (cells != null) { foreach (Cell c in cells) { if (c != null) { c.inUse = false; c.item = null; //c.overlapped = false; //s.ShowImage(); if (c.GetSlot() != null && c.GetSlot() != this.slot) { c.GetSlot().UnsetCell();// RemoveDragDropItem(true); } } } cells = null; } } public void AddToContainedItems(ItemUI item) { ContainedItems.Add(item); item.ParentContainer = this; } public void RemoveFromContainedItems(ItemUI item) { ContainedItems.Remove(item); item.ParentContainer = null; } public void FitImageInSlot(Vector2 size) { //Debug.Log("FitImageInSlot: " + image.transform.name); float ratio = size.y / image.rectTransform.sizeDelta.y; rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y); image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y); backdropImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); backdropImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y); emptyGridContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, size.x); emptyGridContainer.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y); /* image.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y);// = new Vector2(image.rectTransform.sizeDelta.x * ratio, size.y); Debug.Log(oldImageSizeDelta + ", " + oldSizeDelta); this.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, size.y); ;*/ //image.transform.localScale *= ratio; //this.scale = scale; //image.transform.localScale *= scale; } public void SetSlot(SlotUI slot) { this.slot = slot; } // TODO: Make sure it was dropped somewhere, if not, return it to the original parent public void ReturnToSlot(bool forceDrop = false) { if (previousSlot != null && (!isDragging || forceDrop)) { //Debug.Log("RETURNED: " + previousSlot.gameObject.name); previousSlot.DropOntoSlot(this.gameObject); } } // Start is called\ before the first frame update void Start() { FindTextMeshProUGUI(); InitializeImageSize(); // TODO: Possibly have item image scale into slot here. imageSizeOnGrid = new Size(width * InventorySystem.instance.DefaultSizeOnGrid.Width, height * InventorySystem.instance.DefaultSizeOnGrid.Height); if (canvas == null) { canvas = SimpleInventorySystem.InventorySystem.instance.inventoryUI; } if (Count == 0) { Count = 1; } SetRenderItemUIPropertyValue(); Rarity r = GetRarity(); if (backdropImage == null) { backdropImage = transform.GetComponent(); } if (backdropImage == null) { Debug.LogError("ItemUI: Item needs at least an Image component."); } else if (r != null) { backdropImage.color = new Color(r.color.r, r.color.g, r.color.b, InventorySystem.instance.ItemBackdropTransparency); } CreateStorageContainer(); //backdropImage.sprite.rect. /*overrideSortingCanvas = gameObject.AddComponent(); if(overrideSortingCanvas != null) { overrideSortingCanvas.overrideSorting = true; overrideSortingCanvas.sortingLayerID = 5; //overrideSortingCanvas.sortingLayerName = "ItemUI"; }*/ } public void InitializeImageSize() { oldImageSizeDelta = image.rectTransform.sizeDelta; oldSizeDelta = this.rectTransform.sizeDelta; if (oldImageSizeDelta == Vector2.zero) { oldImageSizeDelta = oldSizeDelta; } if (oldSizeDelta == Vector2.zero) { oldSizeDelta = oldImageSizeDelta; } } public Orientation ImageOrientation() { return imageOrientation; } public Size SizeAfterOrientation() { //Debug.Log(imageOrientation); if (imageOrientation == Orientation.Landscape) { if (width >= height) { return new Size(width, height); } else { return new Size(height, width); } } else { if (height >= width) { return new Size(width, height); } else { return new Size(height, width); } } } public void HideSlots() { if (cells != null) { Cell previousCell = slot.cell; foreach (Cell cell in cells) { if (cell != null) { SlotUI cellSlot = cell.GetSlot(); if (cellSlot != null) { // && !slot.useImageAsSlotHolder) cellSlot.HideImage(); } } } } } public void HideEmptyGrid() { if (emptyGridContainer != null) { emptyGridContainer.gameObject.SetActive(false); } } public void ShowEmptyGrid() { if (emptyGridContainer != null) { emptyGridContainer.gameObject.SetActive(true); } } public void SetSlots(List cellList) { cells = new Cell[cellList.Count]; for (int i = 0; i < cellList.Count; i++) { if (cellList[i] != null) { cells[i] = cellList[i]; cells[i].inUse = true; cells[i].item = this; } } } public bool IsSingleCellItem() { return width == 1 && height == 1; } public bool AddToStack(int value = 1) { if (Stackable && Count < StackLimit) { Count+=value; return true; } return false; } public bool RemoveFromStack(int value = 1) { if (Stackable && Count > 0) { Count-= value; return true; } return false; } void FixedUpdate() { } // Update is called once per frame void Update() { if (isDragging) { // TODO: fix this rectTransform.position = InventorySystem.instance.MouseInCanvasPosition; } if (PointerIsHoveredOver && InventorySystem.instance.PressedEquipItemKey(false)) { QuickMove(); // TODO: see if more needs to be implemented here. return; } if (PointerIsHoveredOver && InventorySystem.instance.PressedDropItemKey(false)) { //Debug.Log("Should be throwing away..."); DropItemAway(); return; } if (PointerIsHoveredOver && !InventorySystem.instance.IsDraggingItem) { if (Input.GetMouseButtonDown(0) && !isDragging && InventorySystem.instance.DraggedItem == null && !slot.DroppedOnFrame) { Debug.Log("Grab and drag"); GrabAndDragItem(); } else if (Input.GetMouseButtonDown(2)) { ShowStorageWindow(); } else if (Input.GetMouseButtonDown(1) && !InventorySystem.instance.IsDraggingItem) { InventorySystem.instance.OpenContextMenu(this); } } if (Input.GetMouseButtonUp(0)) { PickedUpOnFrame = false; } if (isDragging) { if (image != null) { image.maskable = false; } if(Count <= 0) { Destroy(gameObject); } if (InventorySystem.instance.PressedKeyRotation(true)) { //Debug.Log("Rotate"); RectTransform handler = (RectTransform)transform; int eulerAngle = Mathf.Abs(Mathf.CeilToInt(handler.rotation.eulerAngles.z)) - 90; //Debug.Log("euler" + eulerAngle); switch (eulerAngle) { case -90: rectTransform.pivot = new Vector2(0, 0); rectTransform.Rotate(new Vector3(0, 0, 1), -90); imageOrientation = (width > height) ? Orientation.Portrait : Orientation.Landscape; break; case 180: rectTransform.pivot = new Vector2(1, 0); handler.Rotate(new Vector3(0, 0, 1), -90); imageOrientation = (width > height) ? Orientation.Landscape : Orientation.Portrait; break; case 90: rectTransform.pivot = new Vector2(1, 1); handler.Rotate(new Vector3(0, 0, 1), -90); imageOrientation = (width > height) ? Orientation.Portrait : Orientation.Landscape; break; default: handler.Rotate(new Vector3(0, 0, 1), -90); handler.localPosition = new Vector3(0, 0, 0); handler.pivot = new Vector2(0, 1); imageOrientation = (width > height) ? Orientation.Landscape : Orientation.Portrait; break; } } } } public void ShowStorageWindow() { if(IsStorageContainer() && (StorageWindow == null || !StorageWindow.gameObject.activeSelf)) { //Debug.Log("Opening Window"); StorageWindow = InventorySystem.instance.OpenWindow().GetComponent(); if(StorageWindow != null && containerUIPrefab != null && !Equipped) { //Debug.Log("Opening Window"); if(container.transform.parent != StorageWindow.StorageContainer.transform) container.transform.SetParent(StorageWindow.StorageContainer.transform, false); container.SetActive(true); StorageWindow.itemUI = this; StorageWindow.gameObject.SetActive(true); } } } public void CreateStorageContainer() { if (container == null && IsStorageContainer()) { //Debug.Log("Item:CreateStorageContainer:" + gameObject.name); container = Instantiate(containerUIPrefab, this.transform, false);// StorageWindow.StorageContainer.transform, false); //itemUI.container.name = itemUI.container.name + " " + inCount; container.GetComponentInChildren().SetAssociatedItemUI(this); //container.SetActive(true); // TODO: modify this StartCoroutine(coroutineA()); } } IEnumerator coroutineA() { // wait for 1 second Debug.Log("coroutineA created"); yield return new WaitForEndOfFrame(); container.SetActive(false); Debug.Log("coroutineA running again"); } public void DropItemAway() { if (pickUp == null) { // TODO: Create a new pickup for items without a gameobject attached Debug.LogError("No in-world gameobject previously attached with itemUI"); } else { InventorySystem.instance.player.DetachItemGameObject(pickUp.ItemGameObject, this); } isDragging = false; SetOverrideSortingCanvasEnabled(false); InventorySystem.instance.DraggedItem = null; UnsetSlot(); } public void SetOverrideSortingCanvasEnabled(bool value) { /* if(overrideSortingCanvas != null) { overrideSortingCanvas.enabled = value; }*/ } public void SetInteractable(bool value) { interactable = value; } public void OnPointerExit(PointerEventData eventData) { //PointerIsHoveredOver = false; } public void OnPointerEnter(PointerEventData eventData) { //PointerIsHoveredOver = true; } public bool IsStorageContainer() { return containerUIPrefab != null && containerUIPrefab.GetComponent() != null; } } }