using System; using System.Collections; using System.Collections.Generic; using System.Runtime.CompilerServices; using PixelCrushers; using PixelCrushers.DialogueSystem; using PixelCrushers.QuestMachine; using UnityEngine; using Action = System.Action; using QuestState = PixelCrushers.QuestMachine.QuestState; namespace Beyond { using Invector.vCharacterController; using Invector.vEventSystems; using System.Linq; using Invector.vCharacterController.vActions; using Invector; using Invector.vItemManager; [vClassHeader("ItemManager")] public partial class bItemManager : vMonoBehaviour, IActionReceiver { #region Delegates /// /// Delegate to filter item usage /// /// target item /// Last results of filter public delegate void CanUseItemDelegate(bItem item, ref List validationList); #endregion Delegates #region Variables [vHelpBox("Place a Inventory Prefab inside your Character, it will be auto-assigned when you enter Playmode." + "\nYou can find the prefab at the Inventory/Prefabs folder", vHelpBoxAttribute.MessageType.Info)] public bInventory inventory; [vHelpBox( "You can find the default ItemListData at the Inventory/ItemListData folder, or create a new list at the Invector Menu", vHelpBoxAttribute.MessageType.Info)] public bItemListData itemListData; public List startItems = new List(); public List equipPoints; public List applyAttributeEvents; public bool debugMode = false; /// /// Events called when item is changed or used /// public OnHandleItemEvent onStartItemUsage, onUseItem, onUseItemFail, onAddItem, onChangeItemAmount; /// /// Events called when add or remove a itemID /// public OnHandleItemIDEvent onAddItemID, onRemoveItemID; public OnCollectItemEvent onCollectItem; /// /// Events called when item is Removed or Destroyed /// public OnChangeItemAmount onDestroyItem, onDropItem; public event Action onFinishItemDestroy; /// /// Event called when inventory open or close /// public OnOpenCloseInventory onOpenCloseInventory; /// /// Events called in Equip or Unequip actions /// public OnChangeEquipmentEvent onEquipItem, onUnequipItem, onFinishEquipItem, onFinishUnequipItem; /// /// Event called whean is changed from method; /// public OnSelectEquipArea onSetLockedToEquip; /// ///Event called when save inventory items using /// public UnityEngine.Events.UnityEvent onSaveItems; /// ///Event called when load inventory items using /// public UnityEngine.Events.UnityEvent onLoadItems; /// /// Equipments in EquipArea /// public Dictionary equipments = new Dictionary(); public Dictionary equipmentsObject = new Dictionary(); protected GameObject equipmentContainer; public List items; internal bool inEquip; private bool usingItem; private float equipTimer; private Animator animator; protected bool inCollectItemRoutine; protected List itemsToCollect = new List(); public vIAnimatorStateInfoController animatorStateInfos; [HideInInspector] public List itemsFilter = new List() { 0 }; /// /// Event to control when use or not an item /// public event CanUseItemDelegate canUseItemDelegate; /// /// Control if it needs to play the animation to Equip or Use the item /// internal bool playItemAnimation { get { return (inventory != null && ((inventory.isOpen && inventory.playItemAnimation) || !inventory.isOpen)) && !temporarilyIgnoreItemAnimation; } } public bool UsingItem { get => usingItem; } /// /// Temporarily ignore the /// internal bool temporarilyIgnoreItemAnimation; internal EquipPoint defaultLeftArmEquipPoint, defaultRightArmEquipPoint; private GuiltGiver guiltGiver; #endregion Variables private IEnumerator Start() { vTime.useUnscaledTime = true; // Finds a Inventory Prefab inside the character if (!inventory) { inventory = transform.GetComponentInChildren(); } if (!inventory) { if (debugMode) { UnityEngine.Debug.LogWarning( "Missing Inventory prefab - You need to Drag and drop a Inventory Prefab inside the Character"); } } if (inventory) { equipmentContainer = new GameObject("Equipment Container"); equipmentContainer.transform.parent = transform; equipmentContainer.transform.localPosition = Vector3.zero; equipmentContainer.transform.localEulerAngles = Vector3.zero; // Initialize all Inventory Actions inventory.GetItemsHandler = GetItems; inventory.GetItemsAllHandler = GetAllItems; inventory.AddItemsHandler = AddItem; inventory.GetAllAmount = GetAllAmount; inventory.onEquipItem.AddListener(EquipItem); inventory.onUnequipItem.AddListener(UnequipItem); inventory.onDropItem.AddListener(DropItem); inventory.onDestroyItem.AddListener(DestroyItem); inventory.onUseItem.AddListener(UseItem); inventory.onOpenCloseInventory.AddListener(OnOpenCloseInventory); var melee = GetComponent(); if (melee) { // Check the vMeleeCombatInput to see the conditions to lock the Inventory Input inventory.IsLockedEvent = () => { return melee.lockInventory; }; } } defaultLeftArmEquipPoint = equipPoints.Find(e => e.equipPointName.Equals("LeftArm")); defaultRightArmEquipPoint = equipPoints.Find(e => e.equipPointName.Equals("RightArm")); // Access the Animator animator = GetComponent(); animatorStateInfos = GetComponent(); yield return new WaitForEndOfFrame(); RegisterDefaultEquipPointListeners(); // Initialize Items items = new List(); if (itemListData) { for (int i = 0; i < startItems.Count; i++) { AddItem(startItems[i], true, null, false); } } guiltGiver = GetComponent(); } /// /// Find and register all components to default equipPoints events /// public virtual void RegisterDefaultEquipPointListeners() { IWeaponEquipmentListener[] defaultEquipPointListeners = GetComponents(); if (defaultEquipPointListeners.Length > 0) { for (int i = 0; i < defaultEquipPointListeners.Length; i++) { if (defaultLeftArmEquipPoint != null) { defaultLeftArmEquipPoint.onInstantiateEquiment.AddListener(defaultEquipPointListeners[i] .SetLeftWeapon); } if (defaultRightArmEquipPoint != null) { defaultRightArmEquipPoint.onInstantiateEquiment.AddListener(defaultEquipPointListeners[i] .SetRightWeapon); } } } } #region Generic Utils /// /// Use it to lock all the input from the vInventory /// /// public virtual void LockInventoryInput(bool value) { if (inventory) { inventory.lockInventoryInput = value; } } /// /// Use it to trigger events when Open or Close the Inventory /// /// protected virtual void OnOpenCloseInventory(bool value) { onOpenCloseInventory.Invoke(value); } /// /// This is just an example of saving the current items /// public void SaveItemsExample() { this.SaveInventory(); } /// /// This is just an example of loading the saved items /// public void LoadItemsExample() { this.LoadInventory(); } /// /// Check vAnimatorTags from the Animator /// /// /// public virtual bool IsAnimatorTag(string tag) { if (animator == null) { return false; } if (animatorStateInfos.isValid()) { if (animatorStateInfos.animatorStateInfos.HasTag(tag)) { return true; } } return false; } #endregion Generic Utils #region Check Items /// /// Check if Area need be locked, based in /// protected virtual void CheckIsLockedToEquip() { var rightArea = System.Array.Find(inventory.equipAreas, a => a.equipPointName.Equals("RightArm")); var leftArea = System.Array.Find(inventory.equipAreas, a => a.equipPointName.Equals("LeftArm")); if (rightArea == null || leftArea == null) { return; } var leftAreaLocked = false; var rightAreaLocked = false; leftAreaLocked = leftArea.currentEquippedItem && rightArea.currentEquippedItem && rightArea.currentEquippedItem.twoHandWeapon; if (leftAreaLocked && leftArea.currentEquippedItem && equipments.ContainsKey(leftArea.currentEquippedItem)) { var equipment = equipments[leftArea.currentEquippedItem]; if (equipment.gameObject.activeSelf) { equipment.gameObject.SetActive(false); } } if (!leftAreaLocked) { rightAreaLocked = rightArea.currentEquippedItem && leftArea.currentEquippedItem && leftArea.currentEquippedItem.twoHandWeapon; if (rightAreaLocked && rightArea.currentEquippedItem && equipments.ContainsKey(rightArea.currentEquippedItem)) { var equipment = equipments[rightArea.currentEquippedItem]; if (equipment.gameObject.activeSelf) { equipment.gameObject.SetActive(false); } } } if (leftAreaLocked != leftArea.isLockedToEquip) { leftArea.isLockedToEquip = leftAreaLocked; onSetLockedToEquip.Invoke(leftArea); } if (rightAreaLocked != rightArea.isLockedToEquip) { rightArea.isLockedToEquip = rightAreaLocked; onSetLockedToEquip.Invoke(rightArea); } } /// /// Check if the current Item is checked with the option , if so, it will Unequip the opposite hand /// /// /// [System.Obsolete("This method will be removed in the future.\n use CheckIsLockedToEquip Method")] protected virtual void CheckTwoHandItem(EquipPoint equipPoint, bItem item) { if (item == null) { return; } var opposite = equipPoints.Find(ePoint => ePoint.area != null && ePoint.equipPointName.Equals("LeftArm") && ePoint.area.currentEquippedItem != null); if (equipPoint.equipPointName.Equals("LeftArm")) { opposite = equipPoints.Find(ePoint => ePoint.area != null && ePoint.equipPointName.Equals("RightArm") && ePoint.area.currentEquippedItem != null); } else if (!equipPoint.equipPointName.Equals("RightArm")) { return; } if (opposite != null && (item.twoHandWeapon || opposite.area.currentEquippedItem.twoHandWeapon)) { opposite.area.RemoveCurrentItem(); } } /// /// Check if the Item List contains a Item ID /// /// Item id /// public virtual bool ContainItem(int id) { return items.Exists(i => i.id == id); } /// /// Check if the Item List contains a Item Name /// /// Item name /// public virtual bool ContainItem(string itemName) { return items.Exists(i => i.name == itemName); } /// /// Check if the list contains a item with a certain amount, or more /// /// Item id /// Item amount /// public virtual bool ContainItem(int id, int amount) { return GetAllAmount(id) >= amount; } /// /// Check if the list contains a item name with certain amount, or more /// /// Item name /// Item amount /// public virtual bool ContainItem(string itemName, int amount) { var item = items.Find(i => i.name == itemName && i.amount >= amount); return item != null ? GetAllAmount(item.id) >= amount : false; } /// /// Check if a EquipArea contains any item equipped /// /// /// index of equip area /// public virtual bool EquipAreaHasSomeItem(int indexOfArea) { var equipArea = inventory.equipAreas[indexOfArea]; return equipArea.equipSlots.Exists(slot => slot.item != null); } /// /// Check if a specific Item ID is equipped on any EquipArea /// /// /// Item id /// public virtual bool ItemIsInSomeEquipArea(int id) { if (!inventory || inventory.equipAreas.Length == 0) { return false; } for (int i = 0; i < inventory.equipAreas.Length; i++) { var equipArea = inventory.equipAreas[i]; if (equipArea.equipSlots.Exists(slot => slot.item.id.Equals(id))) { return true; } } return false; } /// /// Check if a specific Item Name is equipped on any EquipArea /// /// /// Item name /// public virtual bool ItemIsInSomeEquipArea(string itemName) { if (!inventory || inventory.equipAreas.Length == 0) { return false; } for (int i = 0; i < inventory.equipAreas.Length; i++) { var equipArea = inventory.equipAreas[i]; if (equipArea.equipSlots.Exists(slot => slot.item.name.Equals(itemName))) { return true; } } return false; } /// /// Check if a specific Item ID is equipped on a specific EquipArea /// /// /// Item id /// index of equip area /// public virtual bool ItemIsInSpecificEquipArea(int id, int indexOfArea) { if (!inventory || inventory.equipAreas.Length == 0 || indexOfArea > inventory.equipAreas.Length - 1) { return false; } var equipArea = inventory.equipAreas[indexOfArea]; if (equipArea.equipSlots.Exists(slot => slot.item.id.Equals(id))) { return true; } else { return false; } } /// /// Check if a specific Item Name is equipped on a specific EquipArea /// /// /// Item name /// index of equip area /// public virtual bool ItemIsInSpecificEquipArea(string itemName, int indexOfArea) { if (!inventory || inventory.equipAreas.Length == 0 || indexOfArea > inventory.equipAreas.Length - 1) { return false; } var equipArea = inventory.equipAreas[indexOfArea]; if (equipArea.equipSlots.Exists(slot => slot.item.name.Equals(itemName))) { return true; } else { return false; } } /// /// Check if a EquipPoint has any item equipped on it /// /// /// EquipPoint name /// public virtual bool EquipPointHasSomeItem(string equipPointName) { return equipPoints.Exists(ep => ep.equipPointName.Equals(equipPointName) && ep.equipmentReference != null && ep.equipmentReference.item != null); } /// /// Check if a specific Item ID is equipped on any EquipPoint /// /// /// Item id /// public virtual bool ItemIsInSomeEquipPont(int id) { return equipPoints.Exists(ep => ep.equipmentReference != null && ep.equipmentReference.item != null && ep.equipmentReference.item.id.Equals(id)); } /// /// Check if a specific Item Name is equipped on any EquipPoint /// /// /// Item name /// public virtual bool ItemIsInSomeEquipPont(string itemName) { return equipPoints.Exists(ep => ep.equipmentReference != null && ep.equipmentReference.item != null && ep.equipmentReference.item.name.Equals(itemName)); } /// /// Check if a specific Item ID is equipped on specific EquipPoint /// /// /// Item id /// EquipPoint name /// public virtual bool ItemIsInSpecificEquipPoint(int id, string equipPointName) { return equipPoints.Exists(ep => ep.equipPointName.Equals(equipPointName) && ep.equipmentReference != null && ep.equipmentReference.item != null && ep.equipmentReference.item.id.Equals(id)); } /// /// Check if a specific Item Name is equipped on specific EquipPoint /// /// /// Item name /// EquipPoint name /// public virtual bool ItemIsInSpecificEquipPoint(string itemName, string equipPointName) { return equipPoints.Exists(ep => ep.equipPointName.Equals(equipPointName) && ep.equipmentReference != null && ep.equipmentReference.item != null && ep.equipmentReference.item.name.Equals(itemName)); } #endregion Check Items #region Get Items /// /// Get all item amount with the same id from your Inventory /// /// /// public virtual int GetAllAmount(int id) { var _items = GetItems(id); int _amount = 0; for (int i = 0; i < _items.Count; i++) { _amount += _items[i].amount; } return _amount; } /// /// Return a list of all items that you have /// /// public virtual List GetItems() { return items; } /// /// Return a list of all items in your ItemListData /// /// public virtual List GetAllItems() { return itemListData ? itemListData.items : null; } /// /// Get a single Item with same id /// /// /// Item id /// public virtual bItem GetItem(int id) { return items.Find(i => i.id == id); } /// /// Get a single Item with same name /// /// /// Item name /// public virtual bItem GetItem(string itemName) { return items.Find(i => i.name == itemName); } /// /// Get the item from a specific equipPoint /// /// EquipPoint name /// Returns the Item (if equipped) on this EquipPoint public virtual bItem GetItemInEquipPoint(string equipPointName) { var equipPoint = equipPoints.Find(ep => ep.equipPointName.Equals(equipPointName)); if (equipPoint != null && equipPoint.equipmentReference != null && equipPoint.equipmentReference.item) { return equipPoint.equipmentReference.item; } else { return null; } } /// /// Get All Items with same id /// /// /// Item id /// public virtual List GetItems(int id) { var _items = items.FindAll(i => i.id == id); return _items; } /// /// Get All Items with same name /// /// /// Item Name /// public virtual List GetItems(string itemName) { var _items = items.FindAll(i => i.name == itemName); return _items; } /// /// Get a list of all Items equipped in the same EquipArea /// /// /// index of equip area /// public virtual List GetItemsInEquipArea(int indexOfArea) { var list = new List(); if (!inventory || inventory.equipAreas.Length == 0 || indexOfArea > inventory.equipAreas.Length - 1) { return list; } var equipArea = inventory.equipAreas[indexOfArea]; var validSlot = equipArea.ValidSlots; for (int i = 0; i < validSlot.Count; i++) { if (validSlot[i].item != null) { list.Add(validSlot[i].item); } } return list; } /// /// Get a list of all Items equipped on all EquipAreas /// /// /// public virtual List GetAllItemInAllEquipAreas() { var list = new List(); if (!inventory || inventory.equipAreas.Length == 0) { return list; } for (int i = 0; i < inventory.equipAreas.Length; i++) { var equipArea = inventory.equipAreas[i]; var validSlot = equipArea.ValidSlots; for (int a = 0; a < validSlot.Count; a++) { if (validSlot[a].item != null) { list.Add(validSlot[a].item); } } } return list; } #endregion Get Items #region Equipment Pooling protected bEquipment EquipEquipment(bItem item, bool startActive = true) { if (equipments.ContainsKey(item)) { if (!startActive) { if (debugMode) { UnityEngine.Debug.Log($"Disable Equipment {equipments[item].gameObject} "); } equipments[item].gameObject.SetActive(false); } else { if (debugMode) { UnityEngine.Debug.Log($"Enable Equipment {equipments[item].gameObject} "); } equipments[item].gameObject.SetActive(true); } return equipments[item]; } else { if (item.originalObject) { var equipment = item.originalObject.GetComponent(); if (equipment != null) { var equipmentClone = Instantiate(item.originalObject); if (!startActive) { if (debugMode) { UnityEngine.Debug.Log( $"Instantiate and disable Equipment {equipmentClone.gameObject} "); } equipmentClone.gameObject.SetActive(false); } else { if (debugMode) { UnityEngine.Debug.Log( $"Instantiate and enable Equipment {equipmentClone.gameObject} "); } } equipmentClone.transform.SetParent(equipmentContainer.transform); equipmentClone.transform.localPosition = Vector3.zero; equipmentClone.transform.localEulerAngles = Vector3.zero; equipment = equipmentClone.GetComponent(); equipments.Add(item, equipment); equipmentsObject.Add(equipmentClone, equipment); return equipment; } else { Debug.Log("eq is null"); } } } return null; } protected bEquipment EquipEquipment(bItem item, Vector3 position, Quaternion rotation, Transform parent = null) { bEquipment equipment = EquipEquipment(item); if (equipment) { if (parent) { equipment.transform.parent = parent; } equipment.transform.position = position; equipment.transform.rotation = rotation; equipment.OnEquip(item); return equipment; } return null; } protected void UnequipEquipment(bItem item) { if (equipments.ContainsKey(item)) { if (debugMode) { UnityEngine.Debug.Log($"Disable Equipment {equipments[item].gameObject} "); } equipments[item].gameObject.SetActive(false); equipments[item].gameObject.transform.SetParent(equipmentContainer.transform); equipments[item].gameObject.transform.localPosition = Vector3.zero; equipments[item].gameObject.transform.localEulerAngles = Vector3.zero; equipments[item].equipPoint = null; equipments[item].OnUnequip(item); } } #endregion Equipment Pooling #region Add/Equip/AutoEquip Item public void AddItemByString(string itemName) { bItem newItem = itemListData.items.Find(item => item.name.Equals(itemName)); AddItem(newItem); } //only works with format itemId:Amount used for public events in editor public void AddItemByID(string itemIdAndAmount) { var data = itemIdAndAmount.Split(':'); if (data.Length < 2) { return; } bItem newItem = itemListData.items.Find(item => item.id == Int32.Parse(data[0])); AddItem(newItem, Int32.Parse(data[1])); } public void AddItemByID(int id) { bItem newItem = itemListData.items.Find(item => item.id == id); AddItem(newItem); } public void AddItemsByID(int id, int amount) { bItem newItem = itemListData.items.Find(item => item.id == id); AddItem(newItem, amount); } public void AddItem(bItem newItem, int amount = 1) { if (!newItem) { #if UNITY_EDITOR Debug.Log("no item found"); #endif return; } ItemReference itemReference = new ItemReference(newItem.id); itemReference.amount = amount; bItemType itemType = newItem.type; itemReference.indexArea = itemType switch { bItemType.Swords or bItemType.Axes or bItemType.MeleeWeapon => 0, bItemType.Quantas => 1, bItemType.Guilts => 3, _ => 2 }; AddItem(itemReference, true); } /// /// Add a new Item Instance to the Inventory /// /// Reference of the Item to be instantiate /// Play the Enable/Disable animation of your item, you can assign an animation to your item in the ItemListData /// Event called when item is created and added to inventory public virtual void AddItem(ItemReference itemReference, bool ignoreItemAnimation = false, UnityEngine.Events.UnityAction onFinish = null, bool showPopup = true) { if (itemReference != null && itemListData != null && itemListData.items.Count > 0) { var item = itemListData.items.Find(t => t.id.Equals(itemReference.id)); if (item) { var sameItems = items.FindAll(i => i.stackable && i.id == item.id && i.amount < i.maxStack); if (sameItems.Count == 0) { var _item = Instantiate(item); _item.name = _item.name.Replace("(Clone)", string.Empty); if (itemReference.attributes != null && _item.attributes != null && item.attributes.Count == itemReference.attributes.Count) { for (int i = 0; i < _item.attributes.Count; i++) { itemReference.attributes[i].CopyTo(_item.attributes[i]); } } _item.amount = 0; for (int i = 0; i < item.maxStack && _item.amount < _item.maxStack && itemReference.amount > 0; i++) { _item.amount++; itemReference.amount--; } //if item does not exist items.Add(_item); onAddItem.Invoke(_item); onAddItemID.Invoke(_item.id); if (showPopup) { CollectedItemInfo collectedItemInfo = new CollectedItemInfo(); collectedItemInfo.amount = _item.amount; collectedItemInfo.item = _item; DisplayCollectedItems(collectedItemInfo); } if (itemReference.addToEquipArea) { itemReference.addToEquipArea = false; AutoEquipItem(_item, itemReference.indexArea, itemReference.autoEquip, ignoreItemAnimation); } if (itemReference.amount > 0) //if filled max stack, add another item->stack { AddItem(itemReference, onFinish: onFinish); } else { onFinish?.Invoke(_item); } } else { //item exists var indexOffItem = items.IndexOf(sameItems[0]); bool changeAmount = false; int diff = 0; for (int i = 0; i < items[indexOffItem].maxStack && items[indexOffItem].amount < items[indexOffItem].maxStack && itemReference.amount > 0; i++) { //add amount of existing item up to max stack items[indexOffItem].amount++; itemReference.amount--; diff++; changeAmount = true; } if (showPopup) { CollectedItemInfo collectedItemInfo = new CollectedItemInfo(); collectedItemInfo.amount = diff; collectedItemInfo.item = items[indexOffItem]; DisplayCollectedItems(collectedItemInfo); } if (changeAmount) { onChangeItemAmount.Invoke(items[indexOffItem]); } if (itemReference.amount > 0) //if filled max stack, add another item->stack { AddItem(itemReference, onFinish: onFinish); } else if (changeAmount) { onFinish?.Invoke(items[indexOffItem]); } } } } inventory.UpdateInventory(); } /// /// Automatically equip the item to empty EquiSlot of a specific EquipArea /// /// /// EquipArea (index) of the Inventory /// Ignore the Enable/Disable animation of your item public virtual void AutoEquipItem(bItem item, int indexArea, bool autoEquip = false, bool ignoreItemAnimation = true) { if (!inventory) { return; } if (inventory.equipAreas != null && inventory.equipAreas.Length > 0 && indexArea < inventory.equipAreas.Length) { var validSlot = inventory.equipAreas[indexArea].equipSlots.Find(slot => slot.isValid && slot.item == null && slot.itemType.Contains(item.type)); if (validSlot == null && autoEquip && inventory.equipAreas[indexArea].currentEquippedSlot && inventory.equipAreas[indexArea].currentEquippedSlot.item == null) { validSlot = inventory.equipAreas[indexArea].currentEquippedSlot; } if (validSlot && !inventory.equipAreas[indexArea].equipSlots.Exists(slot => slot.item == item)) { var indexOfSlot = inventory.equipAreas[indexArea].equipSlots.IndexOf(validSlot); if (validSlot.item != item) { EquipItemToEquipSlot(indexArea, indexOfSlot, item, autoEquip, ignoreItemAnimation); } } } else { if (debugMode) { UnityEngine.Debug.LogWarning("Fail to auto equip " + item.name + " on equipArea " + indexArea); } } } /// /// Equip a specific Item to a specific EquipArea, this method is called internally by the Event from the Inventory /// /// /// protected virtual void EquipItem(bEquipArea equipArea, bItem item) { CheckIsLockedToEquip(); if (!item) { return; } item.isEquiped = true; onEquipItem.Invoke(equipArea, item); if (debugMode) { UnityEngine.Debug.Log($"Start Equip {item} "); } inventory.UpdateInventory(); if (item != equipArea.currentEquippedItem) { if (debugMode) { UnityEngine.Debug.Log( $"Not Current Equip {item} {equipArea.indexOfEquippedItem}", equipArea.currentEquippedItem); } EquipEquipment(item, false); onFinishEquipItem?.Invoke(equipArea, item); if (debugMode) { UnityEngine.Debug.Log($"Finish Equip {item} "); } return; } else { UnityEngine.Debug.Log($"equip area the same {item} "); } var equipPoint = equipPoints.Find(ep => ep.equipPointName == equipArea.equipPointName); if (equipPoint != null && item != null && equipPoint.equipmentReference.item != item) { if (item.originalObject) { var equipment = item.originalObject.GetComponentInChildren(); if (equipment != null) { equipPoint.area = equipArea; StartCoroutine(EquipItemRoutine(equipPoint, item, () => { onFinishEquipItem?.Invoke(equipArea, item); })); } } } } /// /// Equip Item Routine /// /// /// /// private IEnumerator EquipItemRoutine(EquipPoint equipPoint, bItem item, UnityEngine.Events.UnityAction onFinish) { LockInventoryInput(true); //if (equipPoint != null) //{ // CheckTwoHandItem(equipPoint, item); //} while (inEquip || IsAnimatorTag("IsEquipping")) { yield return new WaitForEndOfFrame(); } if (!equipPoint.area.isLockedToEquip && playItemAnimation) { if (debugMode) { UnityEngine.Debug.Log($"Play Equip Animation {item} "); } equipTimer = item.enableDelayTime; animator.SetBool("FlipEquip", equipPoint.equipPointName.Contains("Left")); animator.CrossFade(item.EnableAnim, 0.25f); } if (!inEquip) { inEquip = true; inventory.canEquip = false; if (equipPoint != null) { if (item.originalObject) { if (equipPoint.equipmentReference != null && equipPoint.equipmentReference.equipedObject != null && equipPoint.equipmentReference.item) { UnequipEquipment(equipPoint.equipmentReference.item); equipPoint.equipmentReference.item = null; } if (!equipPoint.area.isLockedToEquip && playItemAnimation && !string.IsNullOrEmpty(item.EnableAnim)) { if (debugMode && equipTimer > 0) { UnityEngine.Debug.Log($"In Equip delay {item} "); } while (equipTimer > 0) { // Debug.Log("equip timer: " + equipTimer + " " + vTime.deltaTime); if (item == null) { break; } yield return null; equipTimer -= vTime.deltaTime; } } inEquip = false; var point = equipPoint.handler.customHandlers.Find(p => p.name == item.customHandler); var equipTransform = point != null ? point : equipPoint.handler.defaultHandler; bEquipment equipedObject = EquipEquipment(item, equipTransform.position, equipTransform.rotation, equipTransform); if (equipPoint.area.isLockedToEquip) { equipedObject.gameObject.SetActive(false); } equipedObject.equipPoint = equipPoint; equipPoint.equipmentReference.item = item; equipPoint.equipmentReference.equipedObject = equipedObject.gameObject; equipPoint.onInstantiateEquiment.Invoke(equipedObject.gameObject); } else if (equipPoint.equipmentReference != null && equipPoint.equipmentReference.equipedObject != null && equipPoint.equipmentReference.item) { UnequipEquipment(equipPoint.equipmentReference.item); equipments[equipPoint.equipmentReference.item].equipPoint = null; equipPoint.equipmentReference.item = null; } } } LockInventoryInput(false); onFinish?.Invoke(); if (debugMode) { UnityEngine.Debug.Log($"Finish Equip {item} "); } inEquip = false; inventory.canEquip = true; } /// /// Equip item to a equipArea on a specific equipSlot /// /// Index of /// Index of Slot in /// to Equip /// Ignore the Enable/Disable animation of your item public virtual void EquipItemToEquipSlot(int indexOfArea, int indexOfSlot, bItem item, bool autoEquip = false, bool ignoreItemAnimation = false) { if (!inventory) { return; } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } if (inventory.equipAreas != null && indexOfArea < inventory.equipAreas.Length) { var area = inventory.equipAreas[indexOfArea]; if (area != null) { area.AddItemToEquipSlot(indexOfSlot, item, autoEquip); } } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } /// /// Equip or change Item to a current equipSlot from a specific equipArea /// /// Item to equip /// Index of Equip area /// Ignore the Enable/Disable animation of your item public virtual void EquipItemToCurrentEquipSlot(bItem item, int indexOfArea, bool ignoreItemAnimation = true) { if (!inventory && items.Count == 0) { return; } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } if (inventory.equipAreas != null && indexOfArea < inventory.equipAreas.Length) { inventory.equipAreas[indexOfArea].AddCurrentItem(item); } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } #endregion Add/Equip/AutoEquip Item #region Unequip Item private float unequipTimer; /// /// Unequips a specific Item from a specific EquipArea, this method is called internally on a Event from the Inventory /// /// /// protected virtual void UnequipItem(bEquipArea equipArea, bItem item) { if (!item) { return; } item.isEquiped = false; onUnequipItem.Invoke(equipArea, item); if (debugMode) { UnityEngine.Debug.Log($"Start Unequip {item}"); } var equipPoint = equipPoints.Find(ep => ep.equipPointName == equipArea.equipPointName && ep.equipmentReference.item != null && ep.equipmentReference.item == item); if (equipPoint != null && item != null) { equipPoint.onInstantiateEquiment.Invoke(null); unequipTimer = item.disableDelayTime; if (item.originalObject) { var equipment = item.originalObject.GetComponentInChildren(); if (equipment != null) { if (!inventory.isOpen && playItemAnimation && !inEquip && equipPoint.equipmentReference.equipedObject.activeInHierarchy) { if (debugMode) { UnityEngine.Debug.Log($"Play Unequip Animation {item}"); } animator.SetBool("FlipEquip", equipArea.equipPointName.Contains("Left")); animator.CrossFade(item.DisableAnim, 0.25f); } StartCoroutine(UnequipItemRoutine(equipPoint, item, () => { onFinishUnequipItem?.Invoke(equipArea, item); })); } } } else if (item != null) { if (debugMode) { UnityEngine.Debug.Log($"Finish Unequip {item}"); } onFinishUnequipItem.Invoke(equipArea, item); } inventory.UpdateInventory(); CheckIsLockedToEquip(); } /// /// Unequips a specific Item /// /// /// Ignore the Enable/Disable animation of your item public virtual void UnequipItem(bItem item, bool ignoreItemAnimation = true) { var equipArea = System.Array.Find(inventory.equipAreas, e => e.ValidSlots.Exists(s => s.item != null && s.item.id.Equals(item.id))); if (equipArea != null) { if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } UnequipItem(equipArea, item); } inventory.UpdateInventory(); if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } /// /// Unequip item of specific area and specific slot /// /// Index of Equip Area /// Index of Slot in Equip Area /// Ignore the Enable/Disable animation of your item public virtual void UnequipItemOfEquipSlot(int indexOfArea, int indexOfSlot, bool ignoreItemAnimation = true) { if (!inventory) { return; } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } if (inventory.equipAreas != null && indexOfArea < inventory.equipAreas.Length) { var area = inventory.equipAreas[indexOfArea]; if (area != null) { area.RemoveItemOfEquipSlot(indexOfSlot); } } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } /// /// Unequip current equiped item of specific area /// /// Index of Equip area /// Ignore the Enable/Disable animation of your item public virtual void UnequipCurrentEquipedItem(int indexOfArea, bool ignoreItemAnimation = true) { if (!inventory && items.Count == 0) { return; } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } if (inventory.equipAreas != null && indexOfArea < inventory.equipAreas.Length) { inventory.equipAreas[indexOfArea].RemoveCurrentItem(); } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } private IEnumerator UnequipItemRoutine(EquipPoint equipPoint, bItem item, UnityEngine.Events.UnityAction onFinish) { LockInventoryInput(true); if (!inEquip) { inEquip = true; inventory.canEquip = false; if (equipPoint != null && equipPoint.equipmentReference != null && equipPoint.equipmentReference.equipedObject != null) { if (!inventory.isOpen && playItemAnimation) { if (debugMode && unequipTimer > 0) { UnityEngine.Debug.Log($"In Unequip delay {item} "); } while (unequipTimer > 0 && !string.IsNullOrEmpty(item.DisableAnim)) { unequipTimer -= vTime.deltaTime; yield return null; } } if (equipPoint != null && equipPoint.equipmentReference != null && equipPoint.equipmentReference.equipedObject) { UnequipEquipment(item); equipPoint.equipmentReference.item = null; } } inEquip = false; inventory.canEquip = true; } else { } if (debugMode) { UnityEngine.Debug.Log($"Finish Unequip {item}"); } onFinish?.Invoke(); LockInventoryInput(false); } #endregion Unequip Item #region Use Item /// /// Check if a item has any condition to be used /// /// /// public bool CanUseItem(bItem item) { if (canUseItemDelegate != null) { List canUse = new List(); canUseItemDelegate.Invoke(item, ref canUse); return !canUse.Contains(false); } return item.canBeUsed; } /// /// Use a specific Item - Called internally on a Event from the Inventory /// /// public virtual void UseItem(bItem item) { if (item) { if (CanUseItem(item)) { StartCoroutine(UseItemRoutine(item)); } else { onUseItemFail.Invoke(item); } } } /// /// Use Item Routine /// /// protected IEnumerator UseItemRoutine(bItem item) { usingItem = true; LockInventoryInput(true); onStartItemUsage.Invoke(item); var canUse = CanUseItem(item); if (canUse) { var time = item.enableDelayTime; if (!inventory.isOpen && playItemAnimation && !string.IsNullOrEmpty(item.EnableAnim)) { animator.SetBool("FlipAnimation", false); animator.CrossFade(item.EnableAnim, 0.25f); while (usingItem && time > 0 && canUse) { canUse = CanUseItem(item); time -= vTime.deltaTime; yield return null; } } if (usingItem && canUse) { bool itemIsOfPopupType = item.type == bItemType.Consumable || item.type == bItemType.ConsumablesFaith || item.type == bItemType.PowerScroll || item.type == bItemType.Resources || item.type == bItemType.Gemstones; //could maybe unify events on item use, so its not mixed between singletons fired and event subscriptions if (bItemCollectionDisplay.Instance && itemIsOfPopupType && item) { var text = $"Used: {item.name}"; //in game bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f); //in menu if (PopupMenuController.Instance != null) { PopupMenuController.Instance.TryToShowPopupMesssage("Used: " + item.name); } } if (item.destroyAfterUse) { item.amount--; } onUseItem.Invoke(item); //handling item attributes here if (item.attributes != null && item.attributes.Count > 0 && applyAttributeEvents.Count > 0 && item.type != bItemType.PowerScroll) { foreach (ApplyAttributeEvent attributeEvent in applyAttributeEvents) { var attributes = item.attributes.FindAll(a => a.name.Equals(attributeEvent.attribute)); var brightnessAttribute = attributes.Find(a => a.name == bItemAttributes.Brightness); TryToGiveGuiltForEatingWrongFruit(attributes, brightnessAttribute); foreach (bItemAttribute attribute in attributes) { attributeEvent.onApplyAttribute.Invoke(attribute.value); } } } if (item.destroyAfterUse && item.amount <= 0 && items.Contains(item)) { DestroyItem(item); } else { onRemoveItemID.Invoke(item.id); } usingItem = false; inventory.CheckEquipmentChanges(); } else { onUseItemFail.Invoke(item); } } else { onUseItemFail.Invoke(item); } LockInventoryInput(false); inventory.UpdateInventory(); } private void TryToGiveGuiltForEatingWrongFruit(List attributes, bItemAttribute brightnessAttribute) { if (brightnessAttribute != null) { if (brightnessAttribute.value < 0) { guiltGiver.GiveGuilt(); attributes.Remove(brightnessAttribute); } } } #endregion Use Item #region DestroyItem Item /// /// Destroy all amount of specific item /// /// public virtual void DestroyItem(bItem item) { DestroyItem(item, item.amount); } /// /// Destroy a specific amount of a specific item /// /// /// public virtual void DestroyItem(bItem item, int amount) { item.amount -= amount; onDestroyItem.Invoke(item, amount); if (item.amount <= 0) { var equipArea = System.Array.Find(inventory.equipAreas, e => e.ValidSlots.Exists(s => s.item != null && s.item.id.Equals(item.id))); if (equipArea != null) { temporarilyIgnoreItemAnimation = true; equipArea.UnequipItem(item); temporarilyIgnoreItemAnimation = false; } var _itemID = item.id; if (items.Contains(item)) { items.Remove(item); } if (equipments.ContainsKey(item)) { var equipment = equipments[item]; if (equipment != null) { Destroy(equipment.gameObject); } equipments.Remove(item); } Destroy(item); onRemoveItemID.Invoke(_itemID); } inventory.UpdateInventory(); onFinishItemDestroy?.Invoke(); } /// /// Destroy all Items from the Inventory /// public virtual void DestroyAllItems() { for (int i = items.Count - 1; i >= 0; i--) { DestroyItem(items[i]); } } /// /// DestroyItem current equiped item of specific EquipArea /// /// Index of Equip Area /// Ignore the Enable/Disable animation of your item public virtual void DestroyCurrentEquipedItem(int indexOfArea, bool ignoreItemAnimation = true) { if (!inventory && items.Count == 0) { return; } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } if (inventory.equipAreas != null && indexOfArea < inventory.equipAreas.Length) { var item = inventory.equipAreas[indexOfArea].currentEquippedItem; if (item) { DestroyItem(item, item.amount); } } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } #endregion DestroyItem Item #region Drop Item /// /// Drop all amount of specific item /// /// public virtual void DropItem(bItem item) { DropItem(item, item.amount); } /// /// Drop a specific amount of a specific Item /// /// /// public virtual void DropItem(bItem item, int amount) { item.amount -= amount; if (item.dropObject != null) { var dropObject = Instantiate(item.dropObject, transform.position, transform.rotation); bItemCollection collection = dropObject.GetComponent(); if (collection != null) { collection.items.Clear(); var itemReference = new ItemReference(item.id); itemReference.amount = amount; itemReference.attributes = new List(item.attributes); collection.items.Add(itemReference); } } onDropItem.Invoke(item, amount); if (item.amount <= 0 && items.Contains(item)) { var equipArea = System.Array.Find(inventory.equipAreas, e => e.ValidSlots.Exists(s => s.item != null && s.item.id.Equals(item.id))); if (equipArea != null) { equipArea.UnequipItem(item); } items.Remove(item); DestroyItem(item); } inventory.UpdateInventory(); } /// /// Drop all Items from the Inventory /// public virtual void DropAllItens() { List itemReferences = new List(); List dropObjects = new List(); ///Remove All items and create Item Reference to Drop for (int i = items.Count - 1; i >= 0; i--) { var item = items[i]; ItemReference itemReference = itemReferences.Find(_item => _item.id == item.id); if (itemReference == null) { itemReference = new ItemReference(item.id); itemReferences.Add(itemReference); dropObjects.Add(item.dropObject); } itemReference.amount += item.amount; DestroyItem(item); } ///Instantiate all Item References for (int i = 0; i < dropObjects.Count; i++) { var dropObjectPrefab = dropObjects[i]; ItemReference itemReference = itemReferences[i]; if (dropObjectPrefab) { var dropObject = Instantiate(dropObjectPrefab, transform.position, transform.rotation); bItemCollection collection = dropObject.GetComponent(); if (!collection) { collection = dropObject.AddComponent(); } if (collection != null) { collection.items.Clear(); collection.items.Add(itemReference); } } } } /// /// Drop the current equipped item from a specific EquipArea /// /// Index of Equip Area /// Ignore the Enable/Disable animation of your item public virtual void DropCurrentEquippedItem(int indexOfArea, bool ignoreItemAnimation = true) { if (!inventory && items.Count == 0) { return; } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = ignoreItemAnimation; } if (inventory.equipAreas != null && indexOfArea < inventory.equipAreas.Length) { var item = inventory.equipAreas[indexOfArea].currentEquippedItem; if (item) { DropItem(item, item.amount); } } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } #endregion Drop Item #region Item Collector /// /// Collect a Item and display the Items collected with a delay /// /// reference of target item /// /// delay to display Collected item, after the items have been added /// Ignore the Enable/Disable animation of your item /// public virtual void CollectItem(ItemReference itemRef, float onCollectDelay = 0, float textDelay = 0, bool ignoreItemAnimation = true) { if (!inCollectItemRoutine) { itemsToCollect.Add(itemRef); StartCoroutine(CollectItemsRoutine(onCollectDelay, textDelay, ignoreItemAnimation)); } else { itemsToCollect.Add(itemRef); } } /// /// Collect a List of Items and display the Items collected with a delay /// /// List of references of target items /// Delay to add items to inventory /// Delay to display Collected item, after the items have been added /// Ignore the Enable/Disable animation of your item /// public virtual void CollectItems(List collection, float onCollectDelay = 0, float textDelay = 0, bool ignoreItemAnimation = true) { foreach (ItemReference reference in collection) { CollectItem(reference, onCollectDelay, textDelay, ignoreItemAnimation); } } /// /// Coroutine to Add to inventory all items in /// /// Delay to add items to inventory /// Delay to display Collected item, after the items have been added /// Ignore the Enable/Disable animation of your item /// protected virtual IEnumerator CollectItemsRoutine(float onCollectDelay = 0, float textDelay = 0, bool ignoreItemAnimation = true) { while (inCollectItemRoutine) { yield return null; } inCollectItemRoutine = true; yield return new WaitForSeconds(onCollectDelay); List collectedItems = new List(); for (int i = 0; i < inventory.equipAreas.Length; i++) { var area = inventory.equipAreas[i]; area.ignoreEquipEvents = true; } for (int i = 0; i < itemsToCollect.Count; i++) { var itemToCollect = itemsToCollect[i]; UnityEngine.Events.UnityAction onFinish = null; CollectedItemInfo collectedItemInfo = new CollectedItemInfo(); collectedItemInfo.amount = itemsToCollect[i].amount; UnityEngine.Events.UnityAction equipAction = null; if (itemToCollect.addToEquipArea) { var autoEquip = itemsToCollect[i].autoEquip; var indexOfArea = itemsToCollect[i].indexArea; itemsToCollect[i].addToEquipArea = false; itemsToCollect[i].autoEquip = false; equipAction = (bItem _item) => { AutoEquipItem(_item, indexOfArea, autoEquip, true); }; } onFinish = (bItem _item) => { collectedItemInfo.item = _item; collectedItems.Add(collectedItemInfo); equipAction?.Invoke(_item); }; AddItem(itemsToCollect[i].Clone(), ignoreItemAnimation, onFinish, true); } inCollectItemRoutine = false; itemsToCollect.Clear(); // StartCoroutine(DisplayCollectedItems(textDelay, collectedItems.ToArray())); List autoEquipItems = new List(); if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = true; } for (int i = 0; i < inventory.equipAreas.Length; i++) { var area = inventory.equipAreas[i]; if (area.isLockedToEquip) { temporarilyIgnoreItemAnimation = true; } else { while (!ignoreItemAnimation && (inEquip || IsAnimatorTag("IsEquipping"))) { yield return null; } } area.ignoreEquipEvents = false; area.EquipCurrentSlot(); if (area.isLockedToEquip) { temporarilyIgnoreItemAnimation = false; } } if (ignoreItemAnimation) { temporarilyIgnoreItemAnimation = false; } } /// /// Show a list of collected item in /// /// /// /// protected virtual IEnumerator DisplayCollectedItems(float delay, params CollectedItemInfo[] _items) { for (int i = 0; i < _items.Length; i++) { onCollectItem.Invoke(_items[i]); if (bItemCollectionDisplay.Instance) { string amountText = (_items[i].amount > 1) ? _items[i].amount.ToString() : null; var text = $"Acquired: {amountText} {_items[i].item.name}"; bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f); } yield return new WaitForSeconds(delay); } } protected virtual void DisplayCollectedItems(CollectedItemInfo item) { if (bItemCollectionDisplay.Instance) { CheckQuestRequirementsForScrolls(); string amountText = (item.amount > 1) ? item.amount.ToString() : null; var text = $"Acquired: {amountText} {item.item.name}"; bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f); } } //method used to check if player has enough scrolls in quest 8 private void CheckQuestRequirementsForScrolls() { if (QuestMachine.GetQuestState("takeBackTheTemple") != QuestState.Active) { return; } bool condition = GetAllAmount(29) >= 5 && GetAllAmount(42) >= 8 && GetAllAmount(39) >= 10; if (condition) { MessageSystem.SendMessage(this, "Scrolls", "Purchased"); } } public void DisplayRemovedItem(bItem item) { StartCoroutine(DisplayRemovedItemCoroutune(item)); } protected virtual IEnumerator DisplayRemovedItemCoroutune(bItem item) { if (bItemCollectionDisplay.Instance) { string amountText = (item.amount > 1) ? item.amount.ToString() : null; var text = $"Sold: {amountText} {item.name}"; bItemCollectionDisplay.Instance.FadeText(text, 4, 0.25f); } yield return new WaitForSeconds(0); } #endregion Item Collector #region IActionReceiver methods /// /// Event called by /// /// public virtual void OnReceiveAction(vTriggerGenericAction action) { var collection = action.GetComponentInChildren(); if (collection != null) { if (collection.items.Count > 0) { List itemCol = collection.items.vCopy(); CollectItems(itemCol, collection.onCollectDelay, collection.textDelay, collection.ignoreItemAnimation); } } } #endregion IActionReceiver methods public struct CollectedItemInfo { public bItem item; public int amount; } } [System.Serializable] public class ItemReference { public int id; public string name; public int amount; public ItemReference(int id) { this.id = id; this.addToEquipArea = true; this.autoEquip = false; } public List attributes; public bool changeAttributes; public bool autoEquip = false; public bool addToEquipArea = true; public int indexArea; public ItemReference Clone() { ItemReference clone = new ItemReference(this.id); clone.name = this.name; clone.amount = this.amount; clone.autoEquip = this.autoEquip; clone.addToEquipArea = this.addToEquipArea; clone.indexArea = this.indexArea; clone.changeAttributes = this.changeAttributes; clone.attributes = this.attributes; return clone; } } [System.Serializable] public class EquipPoint { #region SeralizedProperties in CustomEditor [SerializeField] public string equipPointName; public EquipmentReference equipmentReference = new EquipmentReference(); [HideInInspector] public bEquipArea area; public vHandler handler = new vHandler(); //public Transform defaultPoint; //public List customPoints = new List(); public OnInstantiateItemObjectEvent onInstantiateEquiment = new OnInstantiateItemObjectEvent(); #endregion SeralizedProperties in CustomEditor } public class EquipmentReference { public GameObject equipedObject; public bItem item; } [System.Serializable] public class ApplyAttributeEvent { [SerializeField] public bItemAttributes attribute; [SerializeField] public OnApplyAttribute onApplyAttribute; } /// /// Interface used to register event from /// public interface IWeaponEquipmentListener { void SetLeftWeapon(GameObject equipment); void SetRightWeapon(GameObject equipment); } }