/// --------------------------------------------- /// Ultimate Character Controller /// Copyright (c) Opsive. All Rights Reserved. /// https://www.opsive.com /// --------------------------------------------- namespace Opsive.UltimateCharacterController.UI { using Opsive.Shared.Events; using Opsive.Shared.Inventory; using Opsive.UltimateCharacterController.Items; using Opsive.UltimateCharacterController.Items.Actions; using UnityEngine; /// /// The PersistentItemMonitor will update the UI for the specified ItemType. /// public class PersistentItemMonitor : ItemMonitor { [Tooltip("The ItemDefinition that the UI should monitor.")] [UnityEngine.Serialization.FormerlySerializedAs("m_ItemType")] [SerializeField] protected ItemDefinitionBase m_ItemDefinition; [Tooltip("Should the UI only be shown when the item is unequipped?")] [SerializeField] protected bool m_AlwaysVisible = true; [Tooltip("Should the UI still be shown when the character dies?")] [SerializeField] protected bool m_VisibleOnDeath = true; public ItemDefinitionBase ItemDefinition { get { return m_ItemDefinition; } set { m_ItemDefinition = value; } } public bool AlwaysVisible { get { return m_AlwaysVisible; } set { m_AlwaysVisible = value; UpdateActiveState(false); } } public bool VisibleOnDeath { get { return m_VisibleOnDeath; } set { m_VisibleOnDeath = value; } } private GameObject m_GameObject; private IItemIdentifier m_ItemIdentifier; private bool m_Alive = true; /// /// Initialize the default values. /// protected override void Awake() { base.Awake(); m_GameObject = gameObject; m_PrimaryCount.text = "0"; } /// /// Attaches the monitor to the specified character. /// /// The character to attach the monitor to. protected override void OnAttachCharacter(GameObject character) { if (m_Character != null) { EventHandler.UnregisterEvent(m_Character, "OnInventoryEquipItem", OnEquipItem); EventHandler.UnregisterEvent(m_Character, "OnDeath", OnDeath); EventHandler.UnregisterEvent(m_Character, "OnRespawn", OnRespawn); } base.OnAttachCharacter(character); if (m_Character == null || m_CharacterInventory == null) { return; } EventHandler.RegisterEvent(m_Character, "OnInventoryEquipItem", OnEquipItem); EventHandler.RegisterEvent(m_Character, "OnDeath", OnDeath); EventHandler.RegisterEvent(m_Character, "OnRespawn", OnRespawn); } /// /// An ItemIdentifier has been picked up within the inventory. /// /// The ItemIdentifier that has been picked up. /// The amount of item picked up. /// Was the item be picked up immediately? /// Should the item be force equipped? protected override void OnPickupItemIdentifier(IItemIdentifier itemIdentifier, int amount, bool immediatePickup, bool forceEquip) { if (itemIdentifier.GetItemDefinition() != m_ItemDefinition) { return; } m_ItemIdentifier = itemIdentifier; if (!m_AlwaysVisible && !ShowCount()) { return; } m_PrimaryCount.text = m_CharacterInventory.GetItemIdentifierAmount(itemIdentifier).ToString(); m_GameObject.SetActive(m_ShowUI); } /// /// Returns true if the ItemMonitor count should be shown. /// /// True if the ItemMonitor count should be shown. private bool ShowCount() { var slotsOccupied = true; var itemIdentifierMatch = false; for (int i = 0; i < m_CharacterInventory.SlotCount; ++i) { var item = m_CharacterInventory.GetActiveItem(i); if (item == null) { slotsOccupied = false; continue; } if (ItemIdentifierMatch(item)) { itemIdentifierMatch = !item.DominantItem; if (!itemIdentifierMatch) { slotsOccupied = true; break; } } } return !slotsOccupied || itemIdentifierMatch; } /// /// An item has been equipped. /// /// The equipped item. /// The slot that the item now occupies. private void OnEquipItem(Item item, int slotID) { UpdateActiveState(!item.DominantItem && ItemIdentifierMatch(item)); } /// /// The DominantItem field has been updated for the specified item. /// /// The Item whose DominantItem field was updated. /// True if the item is now a dominant item. protected override void OnUpdateDominantItem(Item item, bool dominantItem) { if (m_CharacterInventory.GetItemIdentifierAmount(item.ItemIdentifier) == 0) { return; } UpdateActiveState(!item.DominantItem && ItemIdentifierMatch(item)); } /// /// Updates the GameObject's activated/deactivated state. /// /// Should the monitor be shown even if the item isn't equipped? private void UpdateActiveState(bool forceActive) { var active = m_ShowUI && (m_VisibleOnDeath || m_Alive) && (m_AlwaysVisible || forceActive || ShowCount()); m_GameObject.SetActive(active); if (active) { m_PrimaryCount.text = m_CharacterInventory.GetItemIdentifierAmount(m_ItemIdentifier).ToString(); } } /// /// Does the item match the ItemIdentifier used by the monitor? /// /// The item that may use the ItemIdentifier. /// True if the item matches the ItemIdentifier used by the monitor. private bool ItemIdentifierMatch(Item item) { if (item.ItemIdentifier.GetItemDefinition() == m_ItemDefinition) { return true; } // The consumable ItemIdentifier may be specified. var itemActions = item.ItemActions; for (int i = 0; i < itemActions.Length; ++i) { var usableItem = itemActions[i] as IUsableItem; if (usableItem == null) { continue; } var consumableItemIdentifier = usableItem.GetConsumableItemIdentifier(); if (consumableItemIdentifier != null && consumableItemIdentifier.GetItemDefinition() == m_ItemDefinition) { return true; } } return false; } /// /// The specified consumable ItemIdentifier has been used. /// /// The Item that has been used. /// The ItemIdentifier that has been used. /// The remaining amount of the specified ItemIdentifier. protected override void OnUseConsumableItemIdentifier(Item item, IItemIdentifier itemIdentifier, int amount) { if (itemIdentifier.GetItemDefinition() != m_ItemDefinition) { return; } m_PrimaryCount.text = amount.ToString(); } /// /// The specified ItemIdentifier amount has been adjusted. /// /// The ItemIdentifier to adjust. /// The amount of ItemIdentifier to adjust. protected override void OnAdjustItemIdentifierAmount(IItemIdentifier itemIdentifier, int amount) { if (itemIdentifier.GetItemDefinition() != m_ItemDefinition) { return; } m_PrimaryCount.text = amount.ToString(); } /// /// The character has died. /// /// The position of the force. /// The amount of force which killed the character. /// The GameObject that killed the character. private void OnDeath(Vector3 position, Vector3 force, GameObject attacker) { m_Alive = false; UpdateActiveState(false); } /// /// The character has respawned. /// private void OnRespawn() { m_Alive = true; UpdateActiveState(false); } /// /// Can the UI be shown? /// /// True if the UI can be shown. protected override bool CanShowUI() { return base.CanShowUI() && (m_VisibleOnDeath || m_Alive) && (m_AlwaysVisible || ShowCount()); } } }