/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.Inventory { using Opsive.Shared.Events; using Opsive.Shared.Game; using Opsive.Shared.Inventory; using Opsive.UltimateCharacterController.Items; using Opsive.UltimateCharacterController.Items.Actions; using Opsive.UltimateCharacterController.Utility; using UnityEngine; using System.Collections.Generic; /// /// The ItemSetManager manages the ItemSets belonging to the character. /// public abstract class ItemSetManagerBase : MonoBehaviour { [Tooltip("Sepcifies the order that the items can be equipped.")] [SerializeField] protected CategoryItemSet[] m_CategoryItemSets; public CategoryItemSet[] CategoryItemSets { get { return m_CategoryItemSets; } set { m_CategoryItemSets = value; } } [System.NonSerialized] protected bool m_Initialized; protected GameObject m_GameObject; protected InventoryBase m_Inventory; protected int[] m_ActiveItemSetIndex; protected int[] m_NextItemSetIndex; private HashSet m_CheckedItemIdentifiers = new HashSet(); protected Dictionary m_CategoryIndexMap; public int[] ActiveItemSetIndex { get { return m_ActiveItemSetIndex; } } public int[] NextItemSetIndex { get { return m_NextItemSetIndex; } } /// /// Initialize the ItemCollection and ItemSet. /// private void Awake() { m_GameObject = gameObject; m_Inventory = m_GameObject.GetCachedComponent(); Initialize(true); EventHandler.RegisterEvent(m_GameObject, "OnInventoryAddItem", OnAddItem); } /// /// Initializes the ItemSetManager. /// /// Should the ItemSet be force initialized? public abstract void Initialize(bool force); /// /// Returns the corresponding category index which maps to the category. /// /// The interested category. /// The corresponding category index which maps to the category. public int CategoryToIndex(IItemCategoryIdentifier category) { if (category == null) { return -1; } if (m_CategoryIndexMap.TryGetValue(category, out var index)) { return index; } return -1; } /// /// Returns the corresponding category index which maps to the ID. /// /// The ID of the category to get. /// The corresponding category index which maps to the ID. public int CategoryIDToIndex(uint categoryID) { for (int i = 0; i < m_CategoryItemSets.Length; ++i) { if (m_CategoryItemSets[i].CategoryID == categoryID) { return i; } } Debug.LogError($"Error: Category with ID {categoryID} cannot be found."); return -1; } /// /// Returns true if the ItemDefinition belongs to the category with the specified index. /// /// The ItemDefinition to determine if it belongs to the category. /// The index of the category which the ItemIdentifier may belong to. /// True if the ItemDefinition belongs to the category with the specified index. public bool IsCategoryMember(ItemDefinitionBase itemDefinition, int categoryIndex) { // If an ItemDefinition doesn't have a category it is a member of every category. if (itemDefinition.GetItemCategory() == null) { return true; } return IsCategoryMember(itemDefinition.GetItemCategory(), categoryIndex); } /// /// Returns true if the CategoryIdentifier belongs to the category with the specified index. /// /// The CategoryIdentifier to determine if it belongs to the category. /// The index of the category which the ItemIdentifier may belong to. /// True if the ItemIdentifier belongs to the category with the specified index. private bool IsCategoryMember(IItemCategoryIdentifier itemCategory, int categoryIndex) { if (categoryIndex >= m_CategoryItemSets.Length) { return false; } if (itemCategory == m_CategoryItemSets[categoryIndex].ItemCategory) { return true; } // Recursively search the parents. var categoryParents = itemCategory.GetDirectParents(); if (categoryParents == null) { return false; } for (int i = 0; i < categoryParents.Count; ++i) { if (IsCategoryMember(categoryParents[i], categoryIndex)) { return true; } } return false; } /// /// Returns true if the ItemDefinitionrepresents the default ItemCategory. /// /// The ItemDefinition to determine if it is the default ItemCategory. /// True if the ItemDefinition represents the default ItemCategory. public bool IsDefaultItemCategory(ItemDefinitionBase itemDefinition) { if (itemDefinition == null) { return false; } var category = itemDefinition.GetItemCategory(); if (category == null) { return false; } return IsDefaultItemCategory(itemDefinition, category); } /// /// Returns true if the ItemCategory represents the default ItemCategory. /// /// The ItemDefinition to determine if it is the default ItemCategory. /// The ItemCategory to determine if it is the default ItemCategory. /// True if the ItemCategory represents the default ItemCategory. private bool IsDefaultItemCategory(ItemDefinitionBase itemDefinition, IItemCategoryIdentifier itemCategory) { var categoryParents = itemCategory.GetDirectParents(); if (categoryParents != null) { for (int i = 0; i < categoryParents.Count; ++i) { if (IsDefaultItemCategory(itemDefinition, categoryParents[i])) { return true; } } } var index = CategoryToIndex(itemCategory); if (index == -1) { return false; } // The default category does not match the active category. Return false. if (m_CategoryItemSets[index].DefaultItemSetIndex != m_ActiveItemSetIndex[index]) { return false; } // The default category is active. Ensure the ItemDefinition is in that ItemSet. var hasItemDefinition = false; var itemSetList = m_CategoryItemSets[index].ItemSetList[m_ActiveItemSetIndex[index]]; for (int i = 0; i < itemSetList.Slots.Length; ++i) { if (IsChildOf(itemDefinition, itemSetList.Slots[i])) { hasItemDefinition = true; break; } } if (!hasItemDefinition) { return false; } return true; } /// /// The inventory has added the specified item. /// /// The item that was added. private void OnAddItem(Item item) { AddItem(item, item.ItemDefinition.GetItemCategory()); } /// /// Adds the item with the specified ItemCategoryIdentifier. /// /// The item that should be added. /// The category that the item should be aded to. private void AddItem(Item item, IItemCategoryIdentifier category) { if (category == null) { Debug.LogError("Error: No category has been specified. Ensure the ItemIdentifier has been added to a category."); return; } AddItemSet(item, category); // The category can have multiple parents. Keep trying to add the item to all of the possible ItemSets. var categoryParents = category.GetDirectParents(); if (categoryParents != null) { for (int i = 0; i < categoryParents.Count; ++i) { AddItem(item, categoryParents[i]); } } } /// /// Adds a new ItemSet for the specified item if it doesn't already exist. /// /// The item to add the ItemSet for. /// The category that the item should be aded to. private void AddItemSet(Item item, IItemCategoryIdentifier category) { // The category may not have been added to the ItemSetManager. if (category == null || !m_CategoryIndexMap.TryGetValue(category, out var categoryIndex)) { return; } var addItemSet = item.UniqueItemSet; List itemSetList; for (int i = 0; i < m_CategoryItemSets.Length; ++i) { itemSetList = m_CategoryItemSets[i].ItemSetList; for (int j = 0; j < itemSetList.Count; ++j) { // If the item instance has already been added then no new item set needs to be created. if (itemSetList[j].ItemIdentifiers[item.SlotID] == item.ItemIdentifier) { addItemSet = false; break; } // The ItemDefinition exists but the ItemIdentifier does not. Populate the ItemIdentifier with the current item and then stop searching. if (itemSetList[j].ItemIdentifiers[item.SlotID] == null && itemSetList[j].Slots[item.SlotID] == item.ItemDefinition) { itemSetList[j].ItemIdentifiers[item.SlotID] = item.ItemIdentifier; // The item definition matches. Newly added items need to have an ItemSet to themselves. var dedicatedItemDefinition = true; for (int k = 0; k < itemSetList[j].Slots.Length; ++k) { if (k == item.SlotID) { continue; } if (itemSetList[j].Slots[k] != null) { dedicatedItemDefinition = false; break; } } if (dedicatedItemDefinition) { addItemSet = false; // Do not break within the loop because multiple definitions may exist for the same identifier. } } } } // If no ItemSet exists with the added Item then add a new ItemSet. itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; if (addItemSet) { var itemSet = new ItemSet(m_Inventory.SlotCount, item.SlotID, item.ItemDefinition, item.ItemIdentifier, string.Empty); // If the parent ItemIdentifier is not null then the new ItemSet should be added after the ItemSets with the same parent. if (item.ItemDefinition.GetParent() != null) { var insertIndex = -1; for (int i = 0; i < itemSetList.Count; ++i) { if (IsChildOf(item.ItemDefinition, itemSetList[i].Slots[item.SlotID])) { // The other slot elements must be empty. var canInsert = true; for (int j = 0; j < itemSetList[i].Slots.Length; ++j) { if (j == item.SlotID) { continue; } if (itemSetList[i].Slots[j] != null) { canInsert = false; break; } } if (canInsert) { insertIndex = i + 1; } } else if (insertIndex != -1) { // The ItemSet should be inserted after the last ItemSet with the same parent. break; } } // Insert the ItemSet with the child ItemDefinition. insertIndex = insertIndex != -1 ? insertIndex : itemSetList.Count; itemSetList.Insert(insertIndex, itemSet); // If the ItemSet was inserted before the default or active index then the index needs to update to stay accurate. if (insertIndex <= m_CategoryItemSets[categoryIndex].DefaultItemSetIndex) { m_CategoryItemSets[categoryIndex].DefaultItemSetIndex += 1; } if (insertIndex <= m_ActiveItemSetIndex[categoryIndex]) { m_ActiveItemSetIndex[categoryIndex] += 1; EventHandler.ExecuteEvent(m_GameObject, "OnItemSetIndexChange", categoryIndex, m_ActiveItemSetIndex[categoryIndex]); } // The ItemSet must be duplicated for any ItemDefinition that has a similar parent. for (int i = itemSetList.Count - 1; i >= 0; --i) { if (IsChildOf(item.ItemDefinition, itemSetList[i].Slots[item.SlotID])) { // Another ItemDefinition must exist in order for the ItemSet to be duplicated. for (int j = 0; j < itemSetList[i].Slots.Length; ++j) { if (j == item.SlotID) { continue; } // The ItemSet is unique. Duplicate it. if (itemSetList[i].Slots[j] != null) { DuplicateItemSet(item, categoryIndex, i); break; } } } } } else { // The ItemDefinition doesn't have a parent. Add the ItemSet to the end of the list. itemSet.Initialize(m_GameObject, this, m_CategoryItemSets[categoryIndex].CategoryID, categoryIndex, itemSetList.Count); // The ItemDefinition may already exists within the ItemSetList. Use the same state name. for (int i = 0; i < itemSetList.Count; ++i) { if (IsChildOf(item.ItemDefinition, itemSetList[i].Slots[item.SlotID]) && !string.IsNullOrEmpty(itemSetList[i].State)) { var dedicatedItemSet = true; for (int j = 0; j < itemSetList[i].Slots.Length; ++j) { if (j == item.SlotID) { continue; } if (itemSetList[i].Slots[j] != null) { dedicatedItemSet = false; break; } } if (dedicatedItemSet) { itemSet.State = itemSetList[i].State; break; } } } itemSetList.Add(itemSet); } } else if (!item.UniqueItemSet) { // The individual ItemSet doesn't need to be added, but it may need to duplicate an existing ItemSet. for (int i = 0; i < itemSetList.Count; ++i) { if (itemSetList[i].Slots[item.SlotID] != item.ItemDefinition || itemSetList[i].ItemIdentifiers[item.SlotID] == item.ItemIdentifier) { continue; } for (int j = 0; j < itemSetList[i].Slots.Length; ++j) { if (j == item.SlotID) { continue; } if (itemSetList[i].Slots[j] != null) { DuplicateItemSet(item, categoryIndex, i); break; } } } } } /// /// Returns true if the possible child ItemDefinition is a child of the possible parent ItemDefinition. /// /// The ItemDefinition that may be a child of the specified parent. /// The ItemDefinition that may be a parent of the specified child. /// True if the child ItemDefinition is a child of the parent ItemDefinition. private bool IsChildOf(ItemDefinitionBase possibleChild, ItemDefinitionBase possibleParent) { if (possibleChild == null || possibleParent == null) { return false; } var itemDefinition = possibleChild; while (itemDefinition != null) { if (itemDefinition == possibleParent) { return true; } itemDefinition = itemDefinition.GetParent(); } return false; } /// /// Duplicates the ItemSet at the specified index. /// /// The item that triggered the duplication. /// The index of the ItemSet category. /// The index of the ItemSet that should be duplicated. private void DuplicateItemSet(Item item, int categoryIndex, int itemSetIndex) { var itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; var duplicatedItemSet = new ItemSet(itemSetList[itemSetIndex]); duplicatedItemSet.State = itemSetList[itemSetIndex].State; duplicatedItemSet.Slots[item.SlotID] = item.ItemDefinition; duplicatedItemSet.ItemIdentifiers[item.SlotID] = item.ItemIdentifier; duplicatedItemSet.Initialize(m_GameObject, this, m_CategoryItemSets[categoryIndex].CategoryID, categoryIndex, itemSetIndex + 1); itemSetList.Insert(itemSetIndex + 1, duplicatedItemSet); // All of the subsequent ItemSets need to update their index. for (int i = itemSetIndex + 2; i < itemSetList.Count; ++i) { itemSetList[i].Index = i; } // If the ItemSet was inserted before the default or active index then the index needs to update to stay accurate. if (itemSetIndex + 1 <= m_CategoryItemSets[categoryIndex].DefaultItemSetIndex) { m_CategoryItemSets[categoryIndex].DefaultItemSetIndex += 1; } if (itemSetIndex + 1 <= m_ActiveItemSetIndex[categoryIndex]) { m_ActiveItemSetIndex[categoryIndex] += 1; EventHandler.ExecuteEvent(m_GameObject, "OnItemSetIndexChange", categoryIndex, m_ActiveItemSetIndex[categoryIndex]); } } /// /// Adds the ItemSet for the specified item if it doesn't already exist. /// /// The item to add the ItemSet for. /// The ItemSet to add. /// Is the ItemSet the default ItemSet within the category? public void AddItemSet(Item item, ItemSet itemSet, bool defaultItemSet) { AddItemSet(item, itemSet, defaultItemSet, item.ItemDefinition.GetItemCategory()); } /// /// Adds the ItemSet for the specified item if it doesn't already exist. /// /// The item to add the ItemSet for. /// The ItemSet to add. /// Is the ItemSet the default ItemSet within the category? /// The category that the ItemSet is trying to be added to. private void AddItemSet(Item item, ItemSet itemSet, bool defaultItemSet, IItemCategoryIdentifier category) { // The category can have multiple parents. Keep trying to add the ItemSet to all of the possible categories. var categoryParents = category.GetDirectParents(); if (categoryParents != null) { for (int i = 0; i < categoryParents.Count; ++i) { AddItemSet(item, itemSet, defaultItemSet, categoryParents[i]); } } // The category may not have been added to the ItemSetManager. if (!m_CategoryIndexMap.TryGetValue(category, out var categoryIndex)) { return; } var addItemSet = true; var itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; for (int i = 0; i < itemSetList.Count; ++i) { var slots = itemSetList[i].Slots; var slotMatch = true; for (int j = 0; j < slots.Length; ++j) { if (slots[j] != itemSet.Slots[j]) { slotMatch = false; break; } } if (slotMatch) { addItemSet = false; break; } } // If the ItemSet doesn't exist then add it to the list. if (addItemSet) { AddItemSet(itemSet, defaultItemSet, categoryIndex); } } /// /// Adds the ItemSet if it doesn't already exist. /// /// The ItemSet to add. /// Is the ItemSet the default ItemSet within the category? /// The category that the ItemSet is trying to be added to. /// Should ItemSets be added to the category parents? public void AddItemSet(ItemSet itemSet, bool defaultItemSet, IItemCategoryIdentifier category, bool addParents) { // The ItemSet must have at least one slot filled. var validItemSet = false; for (int i = 0; i < itemSet.Slots.Length; ++i) { if (itemSet.Slots[i] != null) { validItemSet = true; break; } } if (!validItemSet) { return; } // The category can have multiple parents. Keep trying to add the ItemSet to all of the possible categories. if (addParents) { var categoryParents = category.GetDirectParents(); if (categoryParents != null) { for (int i = 0; i < categoryParents.Count; ++i) { AddItemSet(itemSet, defaultItemSet, categoryParents[i], addParents); } } } // The category may not have been added to the ItemSetManager. if (!m_CategoryIndexMap.TryGetValue(category, out var categoryIndex)) { return; } // Ensure the ItemSet is unique. var itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; for (int i = 0; i < itemSetList.Count; ++i) { var itemDefinitionMatch = true; for (int j = 0; j < itemSetList[i].Slots.Length; ++j) { if (itemSet.Slots[j] != itemSetList[i].Slots[j]) { itemDefinitionMatch = false; break; } } if (itemDefinitionMatch) { return; } } // The ItemSet is unique. Add it to the list. AddItemSet(itemSet, defaultItemSet, categoryIndex); } /// /// Adds the ItemSet. /// /// The ItemSet to add. /// Is the ItemSet the default ItemSet within the category? /// The index of the category that the ItemSet is being added to. private void AddItemSet(ItemSet itemSet, bool defaultItemSet, int categoryIndex) { var itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; itemSet = new ItemSet(itemSet); itemSetList.Add(itemSet); // The ItemSet must be initialized. itemSet.Initialize(m_GameObject, this, m_CategoryItemSets[categoryIndex].CategoryID, categoryIndex, itemSetList.Count - 1); // The ItemSet can be default if no existing ItemSets are the default ItemSet. if (defaultItemSet && m_CategoryItemSets[categoryIndex].DefaultItemSetIndex == -1) { m_CategoryItemSets[categoryIndex].DefaultItemSetIndex = itemSetList.Count - 1; } } /// /// Returns the ItemSet that the item belongs to. /// /// The item to get the ItemSet of. /// The index of the ItemSet category. /// Should the ItemSet be checked to see if it is valid?. /// The ItemSet that the item belongs to. public int GetItemSetIndex(Item item, int categoryIndex, bool checkIfValid) { if (categoryIndex == -1) { return -1; } // The ItemSet may be in the process of being changed. Test the next item set first to determine if this item set should be returned. List itemSetList; if (m_NextItemSetIndex[categoryIndex] != -1) { itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; var itemSet = itemSetList[m_NextItemSetIndex[categoryIndex]]; if (itemSet.ItemIdentifiers[item.SlotID] == item.ItemIdentifier && (!checkIfValid || IsItemSetValid(categoryIndex, m_NextItemSetIndex[categoryIndex], false))) { return m_NextItemSetIndex[categoryIndex]; } } var itemCount = m_Inventory.GetItemIdentifierAmount(item.ItemIdentifier); // Search through all of the ItemSets for one that contains the specified item. itemSetList = m_CategoryItemSets[categoryIndex].ItemSetList; var validItemSet = -1; for (int i = 0; i < itemSetList.Count; ++i) { // The ItemSet must contain the item at the specified slot in addition to being a valid ItemSet. if (itemSetList[i].ItemIdentifiers[item.SlotID] == item.ItemIdentifier && (!checkIfValid || IsItemSetValid(categoryIndex, i, false))) { // The ItemSet is valid, but do not return it immediately if the ItemSet uses more than one ItemDefinitions. This will prevent a dual wield ItemSet from equipping // when a single item was picked up. var validSlotCount = 1; for (int j = 0; j < itemSetList[i].ItemIdentifiers.Length; ++j) { if (j == item.SlotID) { continue; } if (IsChildOf(item.ItemDefinition, itemSetList[i].Slots[j])) { validSlotCount++; } } if (itemCount == validSlotCount) { return i; } else if (validItemSet == -1) { validItemSet = i; } } } return validItemSet; } /// /// Returns the default ItemSet index for the specified category index. /// /// The index of the cateogry to get the default ItemSet index of. /// The default ItemSet index for the specified category index. public int GetDefaultItemSetIndex(int categoryIndex) { if (categoryIndex == -1) { return -1; } return m_CategoryItemSets[categoryIndex].DefaultItemSetIndex; } /// /// Returns the target ItemSet index for the specified category index based on the allowed slots bitwise mask. /// /// The index of the cateogry to get the target ItemSet index of. /// The bitwise mask indicating which slots are allowed. /// The target ItemSet index for the specified category index. public int GetTargetItemSetIndex(int categoryIndex, int allowedMask) { if (categoryIndex == -1) { return -1; } var itemSetIndex = m_ActiveItemSetIndex[categoryIndex]; if (IsItemSetValid(categoryIndex, itemSetIndex, false, allowedMask)) { return itemSetIndex; } // Check the special cases before looping through the entire item set list. // Determine if the previous item set is similar to the current item set. var itemSetListCount = m_CategoryItemSets[categoryIndex].ItemSetList.Count; var prevItemSetIndex = itemSetIndex - 1; if (prevItemSetIndex < 0) { prevItemSetIndex = itemSetListCount - 1; } if (itemSetIndex != -1 && prevItemSetIndex != itemSetIndex && IsItemSetValid(categoryIndex, prevItemSetIndex, false, allowedMask)) { for (int i = 0; i < m_CategoryItemSets[categoryIndex].ItemSetList[prevItemSetIndex].Slots.Length; ++i) { var prevSlots = m_CategoryItemSets[categoryIndex].ItemSetList[prevItemSetIndex].Slots; if (m_CategoryItemSets[categoryIndex].ItemSetList[itemSetIndex].Slots[i] == prevSlots[i] && prevSlots[i] != null) { // At least one definition matches. Switch to that ItemSet. return prevItemSetIndex; } } } // Check the default item set. if (IsItemSetValid(categoryIndex, m_CategoryItemSets[categoryIndex].DefaultItemSetIndex, false, allowedMask)) { return m_CategoryItemSets[categoryIndex].DefaultItemSetIndex; } // Keep checking the ItemSets until a valid item set exists. var iterCount = 0; do { if (iterCount == itemSetListCount) { // No valid ItemSet was found. return -1; } iterCount++; itemSetIndex = (itemSetIndex + 1) % itemSetListCount; } while (itemSetIndex == prevItemSetIndex || itemSetIndex == m_CategoryItemSets[categoryIndex].DefaultItemSetIndex || !IsItemSetValid(categoryIndex, itemSetIndex, false, allowedMask)); return itemSetIndex; } /// /// Returns true if the specified ItemSet is valid. A valid ItemSet means the character has all of the items specified in the inventory. /// /// The index of the ItemSet category. /// The ItemSet within the category. /// Should the ItemSet be checked if it can be switched to? /// The bitwise mask indicating which slots are allowed. /// True if the specified ItemSet is valid. public bool IsItemSetValid(int categoryIndex, int itemSetIndex, bool checkIfCanSwitchTo, int allowedSlotsMask = -1) { if (itemSetIndex == -1 || itemSetIndex >= m_CategoryItemSets[categoryIndex].ItemSetList.Count) { return false; } var itemSet = m_CategoryItemSets[categoryIndex].ItemSetList[itemSetIndex]; // The ItemSet isn't valid if it isn't enabled. if (!itemSet.Enabled) { return false; } // The ItemSet may not be able to be switched to. if (checkIfCanSwitchTo && !itemSet.CanSwitchTo) { return false; } var requiredCount = 0; var availableCount = 0; m_CheckedItemIdentifiers.Clear(); for (int i = 0; i < itemSet.Slots.Length; ++i) { if (itemSet.Slots[i] == null) { continue; } // If the ItemIdentifier is null then the item hasn't been added yet. if (itemSet.ItemIdentifiers[i] == null) { return false; } // The item may not be in the allowed layer mask. if (allowedSlotsMask != -1 && m_CategoryItemSets[categoryIndex].DefaultItemSetIndex != itemSetIndex && !MathUtility.InLayerMask(i, allowedSlotsMask)) { return false; } // It only takes one item for the ItemSet not to be valid. var item = m_Inventory.GetItem(itemSet.ItemIdentifiers[i], i); if (item == null) { return false; } // Usable items may not be able to be equipped if they don't have any consumable ItemIdentifiers left. for (int j = 0; j < item.ItemActions.Length; ++j) { var usableItem = item.ItemActions[j] as IUsableItem; if (usableItem != null) { if (!usableItem.CanEquipEmptyItem && usableItem.GetConsumableItemIdentifier() != null && m_Inventory.GetItemIdentifierAmount(usableItem.GetConsumableItemIdentifier()) == 0) { return false; } } } // Remember the count to ensure the correct number of items exist within the inventory. requiredCount++; if (!m_CheckedItemIdentifiers.Contains(item.ItemIdentifier)) { availableCount += m_Inventory.GetItemIdentifierAmount(item.ItemIdentifier); m_CheckedItemIdentifiers.Add(item.ItemIdentifier); } } // Ensure the inventory has the number of items required for the current ItemSet. if (availableCount < requiredCount) { return false; } return true; } /// /// Returns the index of the ItemSet that is next or previous in the list. /// /// The category of ItemSets to get. /// The current ItemSet index. /// Should the next ItemSet be retrieved? If false the previous ItemSet will be retrieved. /// The index of the ItemSet that is next or previous in the list. public int NextActiveItemSetIndex(int categoryIndex, int currentItemSetIndex, bool next) { if (currentItemSetIndex == -1) { return -1; } var itemSetListCount = m_CategoryItemSets[categoryIndex].ItemSetList.Count; // The ItemSet can't be switched if there are zero or only one ItemSets. if (itemSetListCount <= 1) { return -1; } var itemSetIndex = currentItemSetIndex; do { itemSetIndex = (itemSetIndex + (next ? 1 : -1)) % itemSetListCount; if (itemSetIndex < 0) { itemSetIndex = itemSetListCount - 1; } } while (itemSetIndex != currentItemSetIndex && !IsItemSetValid(categoryIndex, itemSetIndex, true)); return itemSetIndex; } /// /// Updates the next ItemSet to the specified value. /// /// The category to update the ItemSet within. /// The ItemSet to set. public void UpdateNextItemSet(int categoryIndex, int itemSetIndex) { // No updates are necessary if the indicies are the same. var nextItemSetIndex = m_NextItemSetIndex[categoryIndex]; if (nextItemSetIndex == itemSetIndex) { return; } var prevItemSetIndex = nextItemSetIndex != -1 ? nextItemSetIndex : m_ActiveItemSetIndex[categoryIndex]; m_NextItemSetIndex[categoryIndex] = itemSetIndex; EventHandler.ExecuteEvent(m_GameObject, "OnItemSetManagerUpdateNextItemSet", categoryIndex, prevItemSetIndex, itemSetIndex); } /// /// Updates the active ItemSet to the specified value. /// /// The category to update the ItemSet within. /// The ItemSet to set. /// The active ItemIdentifiers. public void UpdateActiveItemSet(int categoryIndex, int itemSetIndex) { // No updates are necessary if the indicies are the same. var activeItemSetIndex = m_ActiveItemSetIndex[categoryIndex]; if (activeItemSetIndex == itemSetIndex) { return; } if (m_ActiveItemSetIndex[categoryIndex] != -1) { m_CategoryItemSets[categoryIndex].ItemSetList[m_ActiveItemSetIndex[categoryIndex]].Active = false; } m_ActiveItemSetIndex[categoryIndex] = itemSetIndex; m_NextItemSetIndex[categoryIndex] = -1; if (itemSetIndex != -1) { m_CategoryItemSets[categoryIndex].ItemSetList[itemSetIndex].Active = true; } string state, newState = null; if (itemSetIndex != -1) { if (!string.IsNullOrEmpty((state = m_CategoryItemSets[categoryIndex].ItemSetList[itemSetIndex].State))) { StateSystem.StateManager.SetState(m_GameObject, state, true); // Store the new state name for testing against. newState = state; } } if (activeItemSetIndex != -1 && !string.IsNullOrEmpty((state = m_CategoryItemSets[categoryIndex].ItemSetList[activeItemSetIndex].State))) { // If the new state is null or different, then deactivate the state of the old item set. if (string.IsNullOrEmpty(newState) || state != newState) { StateSystem.StateManager.SetState(m_GameObject, state, false); } } EventHandler.ExecuteEvent(m_GameObject, "OnItemSetManagerUpdateItemSet", categoryIndex, itemSetIndex); } /// /// Sets the default ItemSet for the specified category. /// /// The category to set the default itemset of. public void SetDefaultItemSet(int categoryIndex) { var itemSetIndex = GetDefaultItemSetIndex(categoryIndex); if (IsItemSetValid(categoryIndex, itemSetIndex, false)) { UpdateActiveItemSet(categoryIndex, itemSetIndex); } } /// /// Returns the ItemIdentifier which should be equipped for the specified slot. /// /// The slot to get the ItemIdentifier of. /// The ItemIdentifier which should be equipped for the specified slot. Can be null. public IItemIdentifier GetEquipItemIdentifier(int slot) { if (slot == -1 || slot >= m_Inventory.SlotCount) { return null; } for (int i = 0; i < m_CategoryItemSets.Length; ++i) { if (m_ActiveItemSetIndex[i] != -1) { var itemSet = m_CategoryItemSets[i].ItemSetList[m_ActiveItemSetIndex[i]]; if (itemSet.Enabled && itemSet.ItemIdentifiers[slot] != null) { return itemSet.ItemIdentifiers[slot]; } } } return null; } /// /// Returns the ItemIdentifier which should be equipped for the specified categoryIndex and slot. /// /// The category to get the ItemIdentifier of. /// The slot to get the ItemIdentifier of. /// The ItemIdentifier which should be equipped for the specified slot. Can be null. public IItemIdentifier GetEquipItemIdentifier(int categoryIndex, int slot) { if (categoryIndex == -1 || categoryIndex >= m_CategoryItemSets.Length || slot == -1 || slot >= m_Inventory.SlotCount) { return null; } if (m_ActiveItemSetIndex[categoryIndex] != -1) { var itemSet = m_CategoryItemSets[categoryIndex].ItemSetList[m_ActiveItemSetIndex[categoryIndex]]; return itemSet.ItemIdentifiers[slot]; } return null; } /// /// Returns the ItemIdentifier which should be equipped for the specified categoryIndex, ItemSet, and slot. /// /// The category to get the ItemIdentifier of. /// The ItemSet to get the ItemIdentifier of. /// The slot to get the ItemIdentifier of. /// The ItemIdentifier which should be equipped for the specified categoryIndex, ItemIdentifier, and slot. Can be null. public IItemIdentifier GetEquipItemIdentifier(int categoryIndex, int targetItemSetIndex, int slot) { if (categoryIndex == -1 || categoryIndex >= m_CategoryItemSets.Length || targetItemSetIndex == -1 || targetItemSetIndex >= m_CategoryItemSets[categoryIndex].ItemSetList.Count || slot == -1 || slot >= m_Inventory.SlotCount) { return null; } return m_CategoryItemSets[categoryIndex].ItemSetList[targetItemSetIndex].ItemIdentifiers[slot]; } /// /// Returns the ItemIdentifier which is going to be equipped next. /// /// The slot to get the ItemIdentifier of. /// The category index of the found ItemIdentifier. /// The ItemIdentifier which is going to be equipped next. Can be null. public IItemIdentifier GetNextItemIdentifier(int slot, out int categoryIndex) { categoryIndex = -1; if (slot == -1 || slot >= m_Inventory.SlotCount) { return null; } for (int i = 0; i < m_CategoryItemSets.Length; ++i) { var index = m_NextItemSetIndex[i] != -1 ? m_NextItemSetIndex[i] : m_ActiveItemSetIndex[i]; if (index == -1) { continue; } categoryIndex = i; return m_CategoryItemSets[i].ItemSetList[index].ItemIdentifiers[slot]; } return null; } /// /// The character has been destroyed. /// private void OnDestroy() { for (int i = 0; i < m_CategoryItemSets.Length; ++i) { for (int j = 0; j < m_CategoryItemSets[i].ItemSetList.Count; ++j) { m_CategoryItemSets[i].ItemSetList[j].OnDestroy(); } } EventHandler.UnregisterEvent(gameObject, "OnInventoryAddItem", OnAddItem); } } }