/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.Character.Abilities.Items
{
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 System.Collections.Generic;
using UnityEngine;
///
/// Equips or unequips an ItemSet. Can be started manually by calling EquipUnequip.StartEquipUnequip(ItemSetIndex).
///
[DefaultStartType(AbilityStartType.ButtonDown)]
[DefaultInputName("Equip First Item", 0)]
[DefaultInputName("Equip Second Item", 1)]
[DefaultInputName("Equip Third Item", 2)]
[DefaultInputName("Equip Fourth Item", 3)]
[DefaultInputName("Equip Fifth Item", 4)]
[DefaultInputName("Equip Sixth Item", 5)]
[DefaultInputName("Equip Seventh Item", 6)]
[DefaultInputName("Equip Eighth Item", 7)]
[DefaultInputName("Equip Ninth Item", 8)]
[DefaultInputName("Equip Tenth Item", 9)]
[AllowDuplicateTypes]
public class EquipUnequip : ItemSetAbilityBase
{
///
/// Specifies when to equip a new Item.
///
public enum AutoEquipType
{
Always = 1, // Always equip a picked up item.
Unequipped = 2, // Equip the item if there are no items equipped.
OutOfUsableItem = 4, // Equip the item if the current item has no more usable ItemIdentifiers left.
NotPreset = 8, // Equip the item if the item hasn't been added to the inventory already.
FirstTime = 16 // Equip the item the first time the item has been added.
}
///
/// Specifies what action take place with the next update.
///
private enum EquipUnequipAction
{
Inactive, // No actions are currently necessary.
Unequip, // The Unequip method should be called.
UnequipComplete, // The UnequipComplete method should be called.
Equip, // The Equip method should be called.
EquipComplete // The EquipComplete method should be called.
}
[Tooltip("Mask which specifies when to auto equip a new item.")]
[HideInInspector] [SerializeField] protected AutoEquipType m_AutoEquip = AutoEquipType.Unequipped | AutoEquipType.OutOfUsableItem | AutoEquipType.NotPreset | AutoEquipType.FirstTime;
[Tooltip("The Item State Index while equipping.")]
[SerializeField] protected int m_EquipItemStateIndex = 4;
[Tooltip("The Item State Index while unequipping.")]
[SerializeField] protected int m_UnequipItemStateIndex = 5;
[Tooltip("The value to add to the Item Substate Index when the character is aiming.")]
[SerializeField] protected int m_AimItemSubstateIndexAddition = 100;
public AutoEquipType AutoEquip { get { return m_AutoEquip; } set { m_AutoEquip = value; } }
private bool m_StartEquipUnequip;
private int m_StartEquipUnequipIndex;
private int m_ActiveItemSetIndex = -1;
private int m_PrevActiveItemSetIndex = -1;
private EquipUnequipAction[] m_EquipUnequipActions;
private Item[] m_EquipItems;
private Item[] m_UnequipItems;
private ScheduledEventBase[] m_ItemEvents;
private bool m_CanEquip;
private bool[] m_EquippingItems;
private bool[] m_UnequippingItems;
private Dictionary m_InventoryAmount = new Dictionary();
private bool m_ImmediateEquipUnequip;
private bool m_PlayEquipAudio;
private bool m_Aiming;
public override bool CanReceiveMultipleStarts { get { return true; } }
public int ActiveItemSetIndex { get { return m_ActiveItemSetIndex; } }
public override bool CanStayActivatedOnDeath { get { return true; } }
///
/// Initialize the default values.
///
public override void Awake()
{
base.Awake();
m_EquipUnequipActions = new EquipUnequipAction[m_Inventory.SlotCount];
m_EquipItems = new Item[m_Inventory.SlotCount];
m_UnequipItems = new Item[m_Inventory.SlotCount];
m_ItemEvents = new ScheduledEventBase[m_Inventory.SlotCount];
m_EquippingItems = new bool[m_Inventory.SlotCount];
m_UnequippingItems = new bool[m_Inventory.SlotCount];
EventHandler.RegisterEvent(m_GameObject, "OnItemPickupStartPickup", WillStartPickup);
EventHandler.RegisterEvent(m_GameObject, "OnItemPickupStopPickup", StopPickup);
EventHandler.RegisterEvent- (m_GameObject, "OnInventoryPickupItem", OnPickupItem);
EventHandler.RegisterEvent(m_GameObject, "OnInventoryPickupItemIdentifier", OnPickupItemIdentifier);
EventHandler.RegisterEvent(m_GameObject, "OnItemSetIndexChange", OnItemSetIndexChange);
// Animation events cannot have multiple parameters so use the event name to determine which slot to equip/unequip.
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequip", OnItemUnequip);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipComplete", OnItemUnequipComplete);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipFirstSlot", OnItemUnequipFirstSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipCompleteFirstSlot", OnItemUnequipCompleteFirstSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipSecondSlot", OnItemUnequipSecondSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipCompleteSecondSlot", OnItemUnequipCompleteSecondSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipThirdSlot", OnItemUnequipThirdSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemUnequipCompleteThirdSlot", OnItemUnequipCompleteThirdSlot);
EventHandler.RegisterEvent(m_GameObject, "OnEquipUnequipVerifyUnequipItem", OnVerifyUnequipItem);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquip", OnItemEquip);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipComplete", OnItemEquipComplete);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipFirstSlot", OnItemEquipFirstSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipCompleteFirstSlot", OnItemEquipCompleteFirstSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipSecondSlot", OnItemEquipSecondSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipCompleteSecondSlot", OnItemEquipCompleteSecondSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipThirdSlot", OnItemEquipThirdSlot);
EventHandler.RegisterEvent(m_GameObject, "OnAnimatorItemEquipCompleteThirdSlot", OnItemEquipCompleteThirdSlot);
EventHandler.RegisterEvent
- (m_GameObject, "OnInventoryRemoveItem", OnRemoveItem);
EventHandler.RegisterEvent(m_GameObject, "OnAimAbilityStart", OnAim);
EventHandler.RegisterEvent(m_GameObject, "OnDeath", OnDeath);
EventHandler.RegisterEvent(m_GameObject, "OnInventoryRespawned", OnInventoryRespawned);
}
///
/// The ItemPickup component is starting to pick up ItemIdentifiers.
///
public void WillStartPickup()
{
// Remember the initial item inventory list to be able to determine if an item has been added.
m_InventoryAmount.Clear();
var allItems = m_Inventory.GetAllItems();
for (int i = 0; i < allItems.Count; ++i) {
// A duplicate item will exist if the item shares IItemIdentifiers.
if (m_InventoryAmount.ContainsKey(allItems[i].ItemIdentifier)) {
continue;
}
m_InventoryAmount.Add(allItems[i].ItemIdentifier, m_Inventory.GetItemIdentifierAmount(allItems[i].ItemIdentifier));
}
m_PlayEquipAudio = true;
}
///
/// The ItemPickup component is no longer picking up any ItemIdentifiers.
///
private void StopPickup()
{
m_PlayEquipAudio = false;
}
///
/// An item has been picked up within the inventory. Determine if the ability should start.
///
/// The item that has been equipped.
/// The amount of item picked up.
/// Was the item be picked up immediately?
/// Should the item be force equipped?
private void OnPickupItem(Item item, int amount, bool immediatePickup, bool forceEquip)
{
// The ability doesn't need to respond if the category doesn't match.
if (!m_ItemSetManager.IsCategoryMember(item.ItemDefinition, m_ItemSetCategoryIndex) || !Enabled) {
return;
}
// Determine if the item should be auto equipped. There are a variety of circumstances which will allow the item to be equipped.
if (ShouldEquip(item.ItemIdentifier, item.SlotID, amount)) {
// The ItemSetManager will manage which items are equipped.
var itemSetIndex = m_ItemSetManager.GetItemSetIndex(item, m_ItemSetCategoryIndex, true);
// The itemSet may not be valid for the item yet.
if (itemSetIndex != -1) {
// The ItemSet can be equipped immediately or play the equip animation. If equipping immediately ensure
// the character starts with the topmost ItemSet no matter the init order.
if (immediatePickup && (forceEquip || m_ActiveItemSetIndex == -1 || itemSetIndex < m_ActiveItemSetIndex)) {
// The ItemSet should be updated immediately.
m_StartEquipUnequipIndex = m_ActiveItemSetIndex = itemSetIndex;
EventHandler.ExecuteEvent(this, "OnEquipUnequipItemSetIndexChange", m_ActiveItemSetIndex);
m_ItemSetManager.UpdateActiveItemSet(m_ItemSetCategoryIndex, m_ActiveItemSetIndex);
for (int i = 0; i < m_Inventory.SlotCount; ++i) {
// The current slot will be updated immediately.
ForceEquipUnequip(i, false);
var itemIdentifier = m_ItemSetManager.GetEquipItemIdentifier(m_ItemSetCategoryIndex, itemSetIndex, i);
if (itemIdentifier == null) {
// Unequip the current item if no items should be equipped with the current item set.
var unequipItem = m_Inventory.GetActiveItem(i);
if (unequipItem != null && m_ItemSetManager.IsCategoryMember(unequipItem.ItemIdentifier.GetItemDefinition(), m_ItemSetCategoryIndex)) {
m_Inventory.UnequipItem(i);
EventHandler.ExecuteEvent(m_GameObject, "OnAbilityUnequipItemComplete", unequipItem, i);
}
continue;
}
// Only manage the ItemIdentifier if the category matches.
if (m_ItemSetManager.IsCategoryMember(itemIdentifier.GetItemDefinition(), m_ItemSetCategoryIndex)) {
var equippedItem = m_Inventory.GetActiveItem(i);
if (equippedItem != null) {
// No changes are necessary if the ItemIdentifier that should be equipped is the same as the ItemIdentifier that is already equipped.
if (itemIdentifier == equippedItem.ItemIdentifier) {
continue;
}
m_Inventory.UnequipItem(i);
EventHandler.ExecuteEvent(m_GameObject, "OnAbilityUnequipItemComplete", equippedItem, i);
}
var equipItem = m_Inventory.GetItem(itemIdentifier, i);
if (equipItem != null) {
equipItem.WillEquip();
EventHandler.ExecuteEvent(m_GameObject, "OnAbilityWillEquipItem", equipItem, i);
equipItem.StartEquip(true);
}
m_Inventory.EquipItem(itemIdentifier, i, !m_PlayEquipAudio);
}
}
} else if (forceEquip) {
StartEquipUnequip(itemSetIndex);
}
} else if (m_ItemSetManager.ActiveItemSetIndex[m_ItemSetCategoryIndex] == -1) {
// The ItemSet isn't currently valid. Set the default ItemSet so at least one ItemSet is active which will allow the states to switch
// the ItemSet when it becomes valid.
m_ItemSetManager.SetDefaultItemSet(m_ItemSetCategoryIndex);
}
}
}
///
/// Should the item be equipped?
///
/// The IItemIdentifier that may be equipped.
/// The ID of the slot may be equipped.
/// The amount of item picked up.
/// True if the item should be equipped.
public bool ShouldEquip(IItemIdentifier itemIdentifier, int slotID, int amount)
{
// The character shouldn't equip the item if an item is currently in use or is reloading.
if (m_CharacterLocomotion.IsAbilityTypeActive