using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using TMPro; using UnityEngine.EventSystems; // TODO: Expand for other measurement systems later namespace SimpleInventorySystem { public enum Orientation { Portrait, Landscape }; [Serializable] public struct Size { public int Width; public int Height; public Size(int width, int height) { this.Width = width; this.Height = height; } public Size(float width, float height) { this.Width = (int)width; this.Height = (int)height; } public int span { get { return Width * Height; } } } public struct KeyInput { public bool pressedKey, holdingKey; public KeyCode keyCode; public KeyInput(KeyCode keyCode) { this.keyCode = keyCode; pressedKey = false; holdingKey = false; } public void Update() { if (Input.GetKeyDown(keyCode) && !pressedKey && !holdingKey) { //Debug.Log("R"); pressedKey = true; } else if (pressedKey && !holdingKey) { holdingKey = true; } else if (Input.GetKeyUp(keyCode)) { //Debug.Log("R - up"); holdingKey = false; pressedKey = false; } } public bool PressedKey(bool singlePress) { return pressedKey && (!singlePress || !holdingKey); } } [Serializable] public class TagSlotPairing { public ItemTags itemTag; public SlotUI slot; public bool HasSlotOccupied() { return slot.GetItemUI() != null; } public bool DropOntoSlot(ItemUI item) { return CanEquip(item) && slot.DropOntoSlot(item.gameObject); } public bool CanEquip(ItemUI item) { return item.ItemTag == itemTag && slot != null && (!HasSlotOccupied() || slot.IsStacking()) && slot.CanDropOntoSlot(); } } [Serializable] public class TagSlotGridPairing { public ItemTags itemTag; public SlotUI slot; [HideInInspector] public GridUI grid; public bool IsSlotOccupied() { return slot.GetItemUI() != null; } public bool DropOntoGrid(ItemUI item) { //List cells = new List(); //bool canMoveInCells = grid.CanMoveInCells(item, slot, cells); bool dropped = CanStore(item) && grid.DropItemOnGrid(item.gameObject); //Debug.Log("IS:" + dropped); return dropped; } public bool CanStore(ItemUI item) { bool preliminaryCheck = item != null && (item.ItemTag == itemTag || itemTag == ItemTags.Any) && slot != null && IsSlotOccupied() && slot.GetItemUI().container != null; bool slotCheck = preliminaryCheck && slot != null && slot.GetItemUI() != null && slot.GetItemUI().container != null; if (!slotCheck) return slotCheck; grid = slot.GetItemUI().container.GetComponent(); bool gridCheck = grid != null; //Debug.Log("IS:" + gridCheck); return slotCheck && gridCheck; } } public class InventorySystem : MonoBehaviour, IPointerClickHandler { public static InventorySystem instance; public Canvas inventoryUI; public Canvas playerUI; ///private TextMeshProUGUI lootMessage; public GameObject InventoryMenuUI; public GameObject LootMenuUI; public GameObject StatsMenuUI; public KeyCode rotateKey; public KeyCode menuKey; public KeyCode interactKey; public KeyCode dropItemKey; public KeyCode equipItemKey; protected KeyInput rotationKeyInput; protected KeyInput menuKeyInput; protected KeyInput interactKeyInput; protected KeyInput dropItemKeyInput; protected KeyInput equipItemKeyInput; [SerializeField] private int DefaultWidthOnGrid = 100; [SerializeField] private int DefaultHeightOnGrid = 100; public Size DefaultSizeOnGrid; public Camera playerCamera; public GameObject EventsObject; private GameObject toolbarEvents; public StandaloneInputModule StandaloneInputModule; public Vector2 MouseInCanvasPosition; public ItemUI DraggedItem; public ContextMenuManagerUI ContextMenuUI; public static List hoverResults; public Player_IS player; public List TagSlotPairings; public List TagSlotGridPairings; public List raritiesList; [Range(0, 1)] public float ItemBackdropTransparency = .5f; public GridUI LootGrid; private Inventory LastLootedInventory; public GameObject StorageWindowPrefab; public Transform DefaultItemSpawn; public enum States { Undefined, Loot, PickUp }; public States CurrentState = States.Undefined; private void Awake() { if (instance == null) { instance = this; } else { // TODO: Test this, make sure only one inventory system is active throughout the game Destroy(gameObject); } DefaultSizeOnGrid = new Size(DefaultWidthOnGrid, DefaultHeightOnGrid); rotationKeyInput = new KeyInput(rotateKey); menuKeyInput = new KeyInput(menuKey); interactKeyInput = new KeyInput(interactKey); dropItemKeyInput = new KeyInput(dropItemKey); equipItemKeyInput = new KeyInput(equipItemKey); toolbarEvents = EventsObject.transform.Find("Toolbar").gameObject; } public Rarity GetRarityFromList(RarityType rarityType) { foreach(Rarity rarity in raritiesList) { if(rarity.rarityType == rarityType) { return rarity; } } return null; } public void SetPlayerMessageToLoot() { } // Start is called before the first frame update void Start() { InventoryMenuUI.SetActive(false); inventoryUI.overrideSorting = true; CheckForRequiredComponents(); } public bool CheckForRequiredComponents() { if (playerCamera == null || !playerCamera.gameObject.activeSelf) { Camera[] cameras = FindObjectsOfType(); foreach(Camera cam in cameras) { if (cam.gameObject.activeSelf) { playerCamera = cam; break; } } if(playerCamera == null) { return false; } } if (player == null) { player = FindObjectOfType(); return false; // TODO: Temporary solution. We will need to find the exact player for the client player. } if(LootGrid == null) { LootGrid = GetComponentInChildren(); return false; } return true; } public GameObject OpenWindow() { if(InventorySystem.instance.StorageWindowPrefab.GetComponent() != null) return Instantiate(InventorySystem.instance.StorageWindowPrefab, inventoryUI.transform); else return null; } // Update is called once per frame void Update() { CheckForRequiredComponents(); rotationKeyInput.Update(); menuKeyInput.Update(); interactKeyInput.Update(); dropItemKeyInput.Update(); equipItemKeyInput.Update(); //else { DetectObject(); } if (menuKeyInput.PressedKey(true)) { if(InventoryMenuUI != null) { ToggleInventory(); } } hoverResults = GetPointerOverUIObject(); } private List GetPointerOverUIObject() { PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current); eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y); List results = new List(); EventSystem.current.RaycastAll(eventDataCurrentPosition, results); List rGOs = new List(); for (int i = 0; i < results.Count; i++) { if (results[i].gameObject.layer == LayerMask.GetMask("Ignore Raycast")) { results.RemoveAt(i); i--; } else// if (results[i].gameObject.layer == LayerMask.GetMask("UI")) { rGOs.Add(results[i].gameObject); } } return rGOs; } public static bool IsMouseOverUI(GameObject go) { if(hoverResults == null || hoverResults.Count == 0) { return false; } return hoverResults.Contains(go); } public static bool IsMouseOverItemUITop(ItemUI item) { if (hoverResults == null || hoverResults.Count == 0) { return false; } foreach(GameObject go in hoverResults) { if(go.GetComponent() != null) { if (go.GetComponent() == item) return true; else return false; } } return false; } private void FixedUpdate() { Vector2 movePos; RectTransformUtility.ScreenPointToLocalPointInRectangle(inventoryUI.transform as RectTransform, Input.mousePosition, inventoryUI.worldCamera, out movePos); MouseInCanvasPosition = InventorySystem.instance.inventoryUI.transform.TransformPoint(movePos); } public void ToggleInventory() { if (InventoryMenuUI.activeInHierarchy) { CloseInventory(); } else { OpenInventory(); } } public void OpenInventory() { InventoryMenuUI.SetActive(true); Cursor.visible = true; Cursor.lockState = CursorLockMode.Confined; toolbarEvents.GetComponent().MoveToTarget(false, true); if(GetComponent() != null) { GetComponent().pauseMenu.PopEscapeHandlerShow(); } } public void CloseInventory() { toolbarEvents.GetComponent().MoveToSource(true, false); Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; InventoryMenuUI.SetActive(false); if (GetComponent() != null) { GetComponent().pauseMenu.PushEscapeHandlerShow(); } } public void OpenContextMenu(MonoBehaviour uiContext) { if (uiContext.GetType() == typeof(ItemUI)) { ContextMenuUI.OpenContextMenu((ItemUI)uiContext); } } private void DetectObject() { CurrentState = States.Undefined; if (playerCamera == null) { //Debug.Log("Uh OHHH. No camera detected"); } else { //Debug.Log("Detecting..."); } //Ray ray = playerCamera.ScreenPointToRay(new Vector2(Screen.width / 2, Screen.height / 2));//controls.Mouse.Position.ReadValue()); Vector3 direction = Vector3.forward; Ray ray = new Ray(playerCamera.transform.position, playerCamera.transform.TransformDirection(direction * 200)); Debug.DrawRay(playerCamera.transform.position, playerCamera.transform.TransformDirection(direction * 200), Color.red); //RaycastHit hit; /*if (Physics.Raycast(ray, out hit)) { // for single hits, i guess... }*/ RaycastHit[] hits = Physics.RaycastAll(ray, 200); for(int i = 0; i < hits.Length; i++) { if (hits[i].collider != null) { //Debug.Log("3D Hit All: " + hits[i].collider.gameObject.name); } if (hits[i].collider != null)// && hit.transform.parent.parent.parent != null) { PickUp response_pickUp = hits[i].collider.transform.GetComponent(); if (response_pickUp && !InventorySystem.instance.IsUsingInventoryMenuUI()) { //Debug.Log("Detecting"); CurrentState = States.PickUp; DisplayMessageSystem.instance.NameOfItemInWorldWithFocus = response_pickUp.itemUI.itemName; //Debug.Log("IS: Detecting PickUp"); if (interactKeyInput.PressedKey(true)) { //Debug.Log("IS: Pickup handle"); player.HandlePickup(response_pickUp); } return; } else { CurrentState = States.Undefined; } //Debug.Log("3D Hit: " + hit.collider.transform.name); // TODO: functionality here Inventory response_inventory = hits[i].collider.transform.GetComponent(); if(response_inventory != null && response_inventory == player.inventory) { continue; // ignore self } if (response_inventory != null && !InventorySystem.instance.IsUsingInventoryMenuUI()) { //Debug.Log("Opening Inventory"); if (interactKeyInput.PressedKey(true)) { OpenInventory(); LootMenuUI.SetActive(true); StatsMenuUI.SetActive(false); Loot(response_inventory); CurrentState = States.Undefined; } else if (!InventorySystem.instance.IsUsingInventoryMenuUI()) { CurrentState = States.Loot; } } else if(!InventorySystem.instance.IsUsingInventoryMenuUI()) { CurrentState = States.Undefined; LootMenuUI.SetActive(false); StatsMenuUI.SetActive(true); } } } /*RaycastHit[] hitsNonAlloc = new RaycastHit[1]; int numberOfHits = Physics.RaycastNonAlloc(ray, hitsNonAlloc); for (int i = 0; i < numberOfHits; i++) { if (hitsNonAlloc[i].collider != null) { Debug.Log("3D Hit Non Alloc All: " + hitsNonAlloc[i].collider.tag); } }*/ } public void Loot(Inventory inventory) { if (inventory != null && inventory != player.inventory && !inventory.hasBeenLooted) { inventory.Loot(); //Debug.Log($"Looting: {inventory.itemUIs.Count}"); StartCoroutine(LootGrid.PopulateItemsWithNewInventory(inventory.itemUIs)); } } /// /// This can be called to check if player is interacting with the Inventory System's UI /// /// public bool IsUsingInventoryMenuUI() { return InventoryMenuUI.activeInHierarchy; } public bool PressedKeyRotation(bool singlePress) { return rotationKeyInput.PressedKey(singlePress); } public bool PressedDropItemKey(bool singlePress) { return dropItemKeyInput.PressedKey(singlePress) && Input.GetMouseButton(0); } public bool PressedEquipItemKey(bool singlePress) { return equipItemKeyInput.PressedKey(singlePress) && Input.GetMouseButton(0); } public void OnPointerClick(PointerEventData eventData) { if(eventData.button == PointerEventData.InputButton.Left && !ContextMenuManagerUI.instance.ItemInspectMenuHasFocus() && ContextMenuManagerUI.instance.IsInspectingItem()) { ContextMenuManagerUI.instance.CloseContextMenu(); } } } }