projectEli/Assets/Inventory System/Scripts/Inventory/InventorySystem.cs
2023-11-02 20:44:07 -04:00

720 lines
26 KiB
C#

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 prioritizeItemStoreFirst;
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 enum ReferenceTypes { SlotUI, GridUI, GridUIFromSlot, TagSlotGridPairUI }
public ReferenceTypes referenceType = ReferenceTypes.SlotUI;
public GameObject ReferencedGrid;
[HideInInspector] public SlotUI slot;
[HideInInspector] public GridUI grid;
public bool lootingGrid = false;
public TagSlotGridPairing()
{
//Debug.Log("this should be called");
SetSlotsOrGrid();
/*if (tagSlotGridPairUI == null && slot == null && tagSlotGridPairUI == null)
{
Debug.LogWarning($"TagSlotGridPairing: This TagSlotGridPairing will not work for {itemTag} on type {referenceType}.");
}*/
}
public void SetSlotsOrGrid()
{
switch (referenceType)
{
case ReferenceTypes.SlotUI:
{
if (ReferencedGrid != null)
slot = ReferencedGrid.GetComponent<SlotUI>();
else
{
// Debug.LogWarning($"TagSlotGridPairing: ReferencedGrid missing.");
}
break;
}
case ReferenceTypes.GridUI:
{
if (ReferencedGrid != null)
grid = ReferencedGrid.GetComponent<GridUI>();
else
{
Debug.LogWarning($"TagSlotGridPairing: ReferencedGrid missing.");
}
break;
}
case ReferenceTypes.GridUIFromSlot:
{
if (ReferencedGrid != null)
{
slot = ReferencedGrid.GetComponent<SlotUI>();
}
else
{
Debug.LogWarning($"TagSlotGridPairing: ReferencedGrid missing.");
}
break;
}
case ReferenceTypes.TagSlotGridPairUI:
{
if (ReferencedGrid != null)
{
Debug.LogWarning($"TagSlotGridPairing: This TagSlotGridPairing may not use {ReferencedGrid.name} as a Referenced Grid because reference type {referenceType} will search for most available slot based on Heiarchy order.");
}
break;
}
}
}
public bool IsSlotOccupied()
{
return slot.GetItemUI() != null;
}
protected bool DropOntoGrid(ItemUI item)
{
//List<GridUI.Cell> cells = new List<GridUI.Cell>();
//bool canMoveInCells = grid.CanMoveInCells(item, slot, cells);
bool dropped = CanStore(item) && grid.DropItemOnGrid(item.gameObject);
//Debug.Log("IS:Dropped:" + dropped);
return dropped;
}
protected bool DropOntoSlot(ItemUI item)
{
bool dropped = CanStore(item) && slot.DropOntoSlot(item.gameObject);
//Debug.Log("IS:Dropped:" + dropped);
return dropped;
}
public bool Drop(ItemUI item)
{
bool dropped = (referenceType == ReferenceTypes.SlotUI) ? DropOntoSlot(item) : DropOntoGrid(item);
return dropped;
}
public bool CanStore(ItemUI item)
{
SetSlotsOrGrid();
bool preliminaryCheck = item != null && (item.ItemTag == itemTag || itemTag == ItemTags.Any) && slot != null;
//Debug.Log("IS:CanStore" + (preliminaryCheck));
//Debug.Log("IS:CanStore" + (slot != null));
bool slotCheck = false;
bool gridCheck = false;
if (slot != null && (referenceType == ReferenceTypes.GridUIFromSlot || referenceType == ReferenceTypes.SlotUI))
{
if (referenceType == ReferenceTypes.GridUIFromSlot)
{
slotCheck = preliminaryCheck && IsSlotOccupied() && slot.GetItemUI().container != null && slot != null && slot.GetItemUI() != null && slot.GetItemUI().container != null;
if (slotCheck)
{
grid = slot.GetItemUI().container.GetComponent<GridUI>();
}
gridCheck = grid != null && !grid.IsAssociatedItem(item) && !grid.ContainsItemFromGrid(item); // TODO: improve on this for stacking
//Debug.Log($"Contains Item From Grid: {gridCheck}");
//TODO: create function to check if item is inside grid.
}
else
{
slotCheck = preliminaryCheck && (!IsSlotOccupied() || slot.GetItemUI().Stackable) && slot != item.GetSlotUI();
//Debug.Log(slotCheck);
gridCheck = true;
}
}
else if (referenceType == ReferenceTypes.GridUI)
{
slotCheck = true;
gridCheck = grid != null && !grid.ContainsItemFromGrid(item);
}
else if (referenceType == ReferenceTypes.TagSlotGridPairUI)
{
slotCheck = true;
TagSlotGridPairUI[] gridPairs = InventorySystem.instance.inventoryUI.GetComponentsInChildren<TagSlotGridPairUI>();
foreach (TagSlotGridPairUI gp in gridPairs)
{
if (gp.IsAllowed(item.ItemTag))
{
grid = gp.GetComponent<GridUI>();
if (grid != null)
{
//Debug.Log($"TagSlotGridPairing: {grid.gameObject.name}");
if (grid.slots != null && grid.slots.Length > 0 && grid.slots[0] != null)
gridCheck = grid.CanMoveInCells(item, grid.slots[0]) && !grid.ContainsItemFromGrid(item);// && grid.associatedItemUI.ContainedItems != null && !grid.associatedItemUI.ContainedItems.Contains(item);
// TODO: improve on this for stacking
if (gridCheck)
{
break;
}
}
}
}
}
//Debug.Log("IS:CanStore" + (slotCheck && 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;
private ItemUI draggedItem;
public ItemUI DraggedItem
{
set { draggedItem = value; IsDraggingItem = true; }
get { return draggedItem; }
}
public ContextMenuManagerUI ContextMenuUI;
public static List<GameObject> hoverResults;
public Player_IS player;
public List<TagSlotPairing> TagSlotPairings;
public List<TagSlotGridPairing> TagSlotGridPairings;
public List<Rarity> raritiesList;
[Range(0, 1)] public float ItemBackdropTransparency = .5f;
public GridUI LootGrid;
private Inventory LastLootedInventory;
public GameObject StorageWindowPrefab;
public GameObject InspectionWindowPrefab;
public Transform DefaultItemSpawn;
[HideInInspector] public bool IsDraggingItem;
public List<GameObject> hResults;
public ItemViewer itemViewer;
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<Camera>();
foreach (Camera cam in cameras)
{
if (cam.gameObject.activeSelf)
{
playerCamera = cam;
break;
}
}
if (playerCamera == null)
{
return false;
}
}
if (player == null)
{
player = FindObjectOfType<Player_IS>();
return false;
// TODO: Temporary solution. We will need to find the exact player for the client player.
}
if (LootGrid == null)
{
LootGrid = GetComponentInChildren<GridUI>();
return false;
}
return true;
}
public GameObject OpenWindow(string windowType)
{
if (windowType == nameof(StorageWindowUI) && InventorySystem.instance.StorageWindowPrefab.GetComponent<StorageWindowUI>() != null)
{
return Instantiate(InventorySystem.instance.StorageWindowPrefab, inventoryUI.transform);
}
else if (windowType == nameof(InspectionWindowUI) && InventorySystem.instance.InspectionWindowPrefab.GetComponent<InspectionWindowUI>() != null)
{
if (itemViewer != null)
{
itemViewer.OpenCamera();
}
return Instantiate(InventorySystem.instance.InspectionWindowPrefab, inventoryUI.transform);
}
else
return null;
}
// Update is called once per frame
void Update()
{
if (DraggedItem == null)
{
IsDraggingItem = false;
}
CheckForRequiredComponents();
rotationKeyInput.Update();
menuKeyInput.Update();
interactKeyInput.Update();
dropItemKeyInput.Update();
equipItemKeyInput.Update();
//else
{
DetectObject();
}
if (menuKeyInput.PressedKey(true))
{
if (InventoryMenuUI != null)
{
ToggleInventory();
}
}
hResults = hoverResults = GetPointerOverUIObject();
}
private List<GameObject> GetPointerOverUIObject()
{
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
List<GameObject> rGOs = new List<GameObject>();
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<BlockRaycast>() != null)
{
//Debug.Log("BlockRaycast");
return false;
}
if (go.GetComponent<ItemUI>() != null)
{
//Debug.Log(hoverResults);
if (go.GetComponent<ItemUI>() == 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)
{
if (DraggedItem != null)
{
Debug.Log("Return to Slot");
DraggedItem.ReturnToSlot(true);
}
CloseInventory();
}
else
{
OpenInventory();
}
}
public void OpenInventory()
{
InventoryMenuUI.SetActive(true);
Cursor.visible = true;
Cursor.lockState = CursorLockMode.Confined;
toolbarEvents.GetComponent<MoveChildrenUI>().MoveToTarget(false, true);
//if (GetComponent<NeoFPSPause>() != null)
//{
// GetComponent<NeoFPSPause>().pauseMenu.PopEscapeHandlerShow();
//}
}
public void CloseInventory()
{
toolbarEvents.GetComponent<MoveChildrenUI>().MoveToSource(true, false);
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
InventoryMenuUI.SetActive(false);
//if (GetComponent<NeoFPSPause>() != null)
//{
// GetComponent<NeoFPSPause>().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<Vector2>());
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<PickUp>();
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<Inventory>();
LootContainer response_lootContainer = hits[i].collider.transform.GetComponent<LootContainer>();
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 (response_lootContainer != null && !InventorySystem.instance.IsUsingInventoryMenuUI())
{
//Debug.Log("Opening Inventory");
if (interactKeyInput.PressedKey(true))
{
OpenInventory();
LootMenuUI.SetActive(true);
StatsMenuUI.SetActive(false);
Loot(response_lootContainer);
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));
}
}
public void Loot(LootContainer lootContainer)
{
if (lootContainer != null && !lootContainer.hasBeenLooted)
{
lootContainer.Loot();
//Debug.Log($"Looting: {inventory.itemUIs.Count}");
StartCoroutine(LootGrid.PopulateItemsWithNewInventory(lootContainer.itemUIs));
}
}
/// <summary>
/// This can be called to check if player is interacting with the Inventory System's UI
/// </summary>
/// <returns></returns>
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();
}
}
}
}