Files
BABA_YAGA/Assets/Third Parties/Opsive/UltimateCharacterController/Scripts/Inventory/ItemSetManagerBase.cs
Scove 3e39117acc Consolidate third-party plugins into Assets/Plugins
Move and consolidate many third-party plugin files and metadata from various locations (notably Assets/Third Parties/Plugins 1 and scattered Opsive/Photon folders) into a unified Assets/Plugins directory. Includes DOTween, PrimeTween, Native/BackroomsNoise, Sirenix/Odin Inspector, and Opsive UltimateCharacterController/shared libs, plus updates to several .meta files and removal of obsolete installer/legacy files. This standardizes plugin layout and cleans up duplicate/obsolete assets.
2026-06-16 18:41:44 +07:00

944 lines
45 KiB
C#

/// ---------------------------------------------
/// 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;
/// <summary>
/// The ItemSetManager manages the ItemSets belonging to the character.
/// </summary>
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<IItemIdentifier> m_CheckedItemIdentifiers = new HashSet<IItemIdentifier>();
protected Dictionary<IItemCategoryIdentifier, int> m_CategoryIndexMap;
public int[] ActiveItemSetIndex { get { return m_ActiveItemSetIndex; } }
public int[] NextItemSetIndex { get { return m_NextItemSetIndex; } }
/// <summary>
/// Initialize the ItemCollection and ItemSet.
/// </summary>
private void Awake()
{
m_GameObject = gameObject;
m_Inventory = m_GameObject.GetCachedComponent<InventoryBase>();
Initialize(true);
EventHandler.RegisterEvent<Item>(m_GameObject, "OnInventoryAddItem", OnAddItem);
}
/// <summary>
/// Initializes the ItemSetManager.
/// </summary>
/// <param name="force">Should the ItemSet be force initialized?</param>
public abstract void Initialize(bool force);
/// <summary>
/// Returns the corresponding category index which maps to the category.
/// </summary>
/// <param name="category">The interested category.</param>
/// <returns>The corresponding category index which maps to the category.</returns>
public int CategoryToIndex(IItemCategoryIdentifier category)
{
if (category == null) {
return -1;
}
if (m_CategoryIndexMap.TryGetValue(category, out var index)) {
return index;
}
return -1;
}
/// <summary>
/// Returns the corresponding category index which maps to the ID.
/// </summary>
/// <param name="categoryID">The ID of the category to get.</param>
/// <returns>The corresponding category index which maps to the ID.</returns>
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;
}
/// <summary>
/// Returns true if the ItemDefinition belongs to the category with the specified index.
/// </summary>
/// <param name="itemDefinition">The ItemDefinition to determine if it belongs to the category.</param>
/// <param name="categoryIndex">The index of the category which the ItemIdentifier may belong to.</param>
/// <returns>True if the ItemDefinition belongs to the category with the specified index.</returns>
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);
}
/// <summary>
/// Returns true if the CategoryIdentifier belongs to the category with the specified index.
/// </summary>
/// <param name="itemCategory">The CategoryIdentifier to determine if it belongs to the category.</param>
/// <param name="categoryIndex">The index of the category which the ItemIdentifier may belong to.</param>
/// <returns>True if the ItemIdentifier belongs to the category with the specified index.</returns>
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;
}
/// <summary>
/// Returns true if the ItemDefinitionrepresents the default ItemCategory.
/// </summary>
/// <param name="itemIdentifier">The ItemDefinition to determine if it is the default ItemCategory.</param>
/// <returns>True if the ItemDefinition represents the default ItemCategory.</returns>
public bool IsDefaultItemCategory(ItemDefinitionBase itemDefinition)
{
if (itemDefinition == null) {
return false;
}
var category = itemDefinition.GetItemCategory();
if (category == null) {
return false;
}
return IsDefaultItemCategory(itemDefinition, category);
}
/// <summary>
/// Returns true if the ItemCategory represents the default ItemCategory.
/// </summary>
/// <param name="itemDefinition">The ItemDefinition to determine if it is the default ItemCategory.</param>
/// <param name="itemCategory">The ItemCategory to determine if it is the default ItemCategory.</param>
/// <returns>True if the ItemCategory represents the default ItemCategory.</returns>
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;
}
/// <summary>
/// The inventory has added the specified item.
/// </summary>
/// <param name="item">The item that was added.</param>
private void OnAddItem(Item item)
{
AddItem(item, item.ItemDefinition.GetItemCategory());
}
/// <summary>
/// Adds the item with the specified ItemCategoryIdentifier.
/// </summary>
/// <param name="item">The item that should be added.</param>
/// <param name="category">The category that the item should be aded to.</param>
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]);
}
}
}
/// <summary>
/// Adds a new ItemSet for the specified item if it doesn't already exist.
/// </summary>
/// <param name="item">The item to add the ItemSet for.</param>
/// <param name="category">The category that the item should be aded to.</param>
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<ItemSet> 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;
}
}
}
}
}
/// <summary>
/// Returns true if the possible child ItemDefinition is a child of the possible parent ItemDefinition.
/// </summary>
/// <param name="possibleChild">The ItemDefinition that may be a child of the specified parent.</param>
/// <param name="categoryIndex">The ItemDefinition that may be a parent of the specified child.</param>
/// <returns>True if the child ItemDefinition is a child of the parent ItemDefinition.</returns>
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;
}
/// <summary>
/// Duplicates the ItemSet at the specified index.
/// </summary>
/// <param name="item">The item that triggered the duplication.</param>
/// <param name="categoryIndex">The index of the ItemSet category.</param>
/// <param name="itemSetIndex">The index of the ItemSet that should be duplicated.</param>
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]);
}
}
/// <summary>
/// Adds the ItemSet for the specified item if it doesn't already exist.
/// </summary>
/// <param name="item">The item to add the ItemSet for.</param>
/// <param name="itemSet">The ItemSet to add.</param>
/// <param name="defaultItemSet">Is the ItemSet the default ItemSet within the category?</param>
public void AddItemSet(Item item, ItemSet itemSet, bool defaultItemSet)
{
AddItemSet(item, itemSet, defaultItemSet, item.ItemDefinition.GetItemCategory());
}
/// <summary>
/// Adds the ItemSet for the specified item if it doesn't already exist.
/// </summary>
/// <param name="item">The item to add the ItemSet for.</param>
/// <param name="itemSet">The ItemSet to add.</param>
/// <param name="defaultItemSet">Is the ItemSet the default ItemSet within the category?</param>
/// <param name="category">The category that the ItemSet is trying to be added to.</param>
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);
}
}
/// <summary>
/// Adds the ItemSet if it doesn't already exist.
/// </summary>
/// <param name="itemSet">The ItemSet to add.</param>
/// <param name="defaultItemSet">Is the ItemSet the default ItemSet within the category?</param>
/// <param name="category">The category that the ItemSet is trying to be added to.</param>
/// <param name="addParents">Should ItemSets be added to the category parents?</param>
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);
}
/// <summary>
/// Adds the ItemSet.
/// </summary>
/// <param name="itemSet">The ItemSet to add.</param>
/// <param name="defaultItemSet">Is the ItemSet the default ItemSet within the category?</param>
/// <param name="categoryIndex">The index of the category that the ItemSet is being added to.</param>
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;
}
}
/// <summary>
/// Returns the ItemSet that the item belongs to.
/// </summary>
/// <param name="item">The item to get the ItemSet of.</param>
/// <param name="categoryIndex">The index of the ItemSet category.</param>
/// <param name="checkIfValid">Should the ItemSet be checked to see if it is valid?.</param>
/// <returns>The ItemSet that the item belongs to.</returns>
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<ItemSet> 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;
}
/// <summary>
/// Returns the default ItemSet index for the specified category index.
/// </summary>
/// <param name="categoryIndex">The index of the cateogry to get the default ItemSet index of.</param>
/// <returns>The default ItemSet index for the specified category index.</returns>
public int GetDefaultItemSetIndex(int categoryIndex)
{
if (categoryIndex == -1) {
return -1;
}
return m_CategoryItemSets[categoryIndex].DefaultItemSetIndex;
}
/// <summary>
/// Returns the target ItemSet index for the specified category index based on the allowed slots bitwise mask.
/// </summary>
/// <param name="categoryIndex">The index of the cateogry to get the target ItemSet index of.</param>
/// <param name="allowedSlotsMask">The bitwise mask indicating which slots are allowed.</param>
/// <returns>The target ItemSet index for the specified category index.</returns>
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;
}
/// <summary>
/// Returns true if the specified ItemSet is valid. A valid ItemSet means the character has all of the items specified in the inventory.
/// </summary>
/// <param name="categoryIndex">The index of the ItemSet category.</param>
/// <param name="itemSetIndex">The ItemSet within the category.</param>
/// <param name="checkIfCanSwitchTo">Should the ItemSet be checked if it can be switched to?</param>
/// <param name="allowedSlotsMask">The bitwise mask indicating which slots are allowed.</param>
/// <returns>True if the specified ItemSet is valid.</returns>
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;
}
/// <summary>
/// Returns the index of the ItemSet that is next or previous in the list.
/// </summary>
/// <param name="categoryIndex">The category of ItemSets to get.</param>
/// <param name="currentItemSetIndex">The current ItemSet index.</param>
/// <param name="next">Should the next ItemSet be retrieved? If false the previous ItemSet will be retrieved.</param>
/// <returns>The index of the ItemSet that is next or previous in the list.</returns>
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;
}
/// <summary>
/// Updates the next ItemSet to the specified value.
/// </summary>
/// <param name="categoryIndex">The category to update the ItemSet within.</param>
/// <param name="itemSetIndex">The ItemSet to set.</param>
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);
}
/// <summary>
/// Updates the active ItemSet to the specified value.
/// </summary>
/// <param name="categoryIndex">The category to update the ItemSet within.</param>
/// <param name="itemSetIndex">The ItemSet to set.</param>
/// <param name="itemIdentifiers">The active ItemIdentifiers.</param>
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);
}
/// <summary>
/// Sets the default ItemSet for the specified category.
/// </summary>
/// <param name="categoryIndex">The category to set the default itemset of.</param>
public void SetDefaultItemSet(int categoryIndex)
{
var itemSetIndex = GetDefaultItemSetIndex(categoryIndex);
if (IsItemSetValid(categoryIndex, itemSetIndex, false)) {
UpdateActiveItemSet(categoryIndex, itemSetIndex);
}
}
/// <summary>
/// Returns the ItemIdentifier which should be equipped for the specified slot.
/// </summary>
/// <param name="slot">The slot to get the ItemIdentifier of.</param>
/// <returns>The ItemIdentifier which should be equipped for the specified slot. Can be null.</returns>
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;
}
/// <summary>
/// Returns the ItemIdentifier which should be equipped for the specified categoryIndex and slot.
/// </summary>
/// <param name="categoryIndex">The category to get the ItemIdentifier of.</param>
/// <param name="slot">The slot to get the ItemIdentifier of.</param>
/// <returns>The ItemIdentifier which should be equipped for the specified slot. Can be null.</returns>
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;
}
/// <summary>
/// Returns the ItemIdentifier which should be equipped for the specified categoryIndex, ItemSet, and slot.
/// </summary>
/// <param name="categoryIndex">The category to get the ItemIdentifier of.</param>
/// <param name="targetItemSetIndex">The ItemSet to get the ItemIdentifier of.</param>
/// <param name="slot">The slot to get the ItemIdentifier of.</param>
/// <returns>The ItemIdentifier which should be equipped for the specified categoryIndex, ItemIdentifier, and slot. Can be null.</returns>
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];
}
/// <summary>
/// Returns the ItemIdentifier which is going to be equipped next.
/// </summary>
/// <param name="slot">The slot to get the ItemIdentifier of.</param>
/// <param name="categoryIndex">The category index of the found ItemIdentifier.</param>
/// <returns>The ItemIdentifier which is going to be equipped next. Can be null.</returns>
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;
}
/// <summary>
/// The character has been destroyed.
/// </summary>
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<Item>(gameObject, "OnInventoryAddItem", OnAddItem);
}
}
}