Toggle Item set when Shootable item has only 1 ammo

nathanj

Active member
Hi, Andrew

This is going to be a bit of a long one, sorry. I'm working through my custom spear throw and have come to another road block. I would like to be able to Equip and Unequip my Spear (Shootable Item) when I only have one piece of ammo but can not figure out how to do this. I will email a link to a project to you privately to demonstrate this.

In the demo scene, I have a Bow (Shootable Item) item that is first added to the player's inventory. When the player picks up a single Arrow (ammo) the Bow (Shootable Item) is equipped. I am able to fire the weapon at this point. However, if I unequip the Bow (Shootable Item) I am unable to equip it again because on the Bow (Shootable Item) I have "Can Equip On Empty" set to false because I only want the bow to be equippable if they have an arrpw in their inventory. The issue is that while they have picked up an arrow (and technically have one), it is not registered in their inventory because it is loaded into the Bow (Shootable Item).

If, however, I collect a second Arrow, I can equip and unequip my Bow as desired.

Loaded.PNG AddedToInventory.PNG

The left image shows the inventory after a single arrow has been collected and the second image shows after a second has been collected

I looked around and see that it can be found with m_LoadedCount of the ItemMonitor script, but from what I can see that can only be read if that specific Item is active - I need to access that Loaded Value of the Bow when the item is not active so I can determine if the Bow can be equipped.


The other issue with this is that I am trying to Unequip the Bow (Shootable Item) if the ammo count is 0. I am using the "OnItemUseConsumableItemIdentifier" event you suggested last week. This is where I am at with that:

Code:
private EquipUnequip[] unequip;
    public int itemSetValue = 20;
    public void Awake()
    {
        EventHandler.RegisterEvent<Item, IItemIdentifier, int>(gameObject, "OnItemUseConsumableItemIdentifier", OnItemUseConsumableItemIdentifier);
    }
    private void Start()
    {
        unequip = gameObject.GetComponent<UltimateCharacterLocomotion>().GetAbilities<EquipUnequip>();
    }
    private void OnItemUseConsumableItemIdentifier(Item item, IItemIdentifier identifier, int amount)
    {
        print(item + " item");
        print(identifier + " identifier");
        print(amount + " amount");

        if (amount == 0 && identifier.ToString() == "BowArrow")
        {
            for (int i = 0; i < unequip.Length; ++i)
            {
                if (unequip[i].ItemSetCategoryIndex == 0)
                {
                    print("Try unequip   " + unequip[i].ItemSetCategoryIndex.ToString());
                    unequip[i].StartEquipUnequip(itemSetValue, true, false);
                    return;
                }
            }
        }
    }
    public void Destroy()
    {
        EventHandler.RegisterEvent<Item, IItemIdentifier, int>(gameObject, "OnItemUseConsumableItemIdentifier", OnItemUseConsumableItemIdentifier);
    }

I have it kind of working but there are a few issues. First, if I try to Unequip the Bow Item Set (Item Set 6) with the above code it doesn't work . If I instead Equip the Body* (Item Set 20) it works in that it unequips the Bow Item Set but I get the following error related to the "Use" Ability.


Code:
NullReferenceException: Object reference not set to an instance of an object
Opsive.UltimateCharacterController.Character.Abilities.Items.Use.CanStopAbility () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/Abilities/Items/Use.cs:825)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion.TryStopAbility (Opsive.UltimateCharacterController.Character.Abilities.Ability ability, System.Boolean force) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1419)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion.TryStopAbility (Opsive.UltimateCharacterController.Character.Abilities.Ability ability) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1401)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.TryStopAbility (Opsive.UltimateCharacterController.Character.Abilities.Ability ability) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:245)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.UpdateAbilityInput (Opsive.UltimateCharacterController.Character.Abilities.Ability[] abilities) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:122)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.UpdateAbilityInput () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:99)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.Update () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:73)

I hope this isn't a pain for you to answer. I've been trying to work through it but I stumped.

*I have set the Body Item Set to "Can Switch To" so I could scroll the bow from equipped to unqueipped.
 
You can get the total ammo amount using a script similar to the one found under "Item Amounts" on this page. The item in question doesn't need to be equipped at the time (e.g. instead of using GetActiveItem, you could just iterate through Inventory.GetAllItems, or keep a reference to the specific item). I.e. you'd just add together the consumable loaded amount + inventory amounts shown in that script.

Also what doesn't work about manually starting EquipUnequip with the bow? Have you tried passing immediateEquipUnequip=true?
 
Hey Again,

Still trying to get the reference to the item when the item is used, you mind having a look at this?

Code:
public class VSUnequipOnSlotEmpty : MonoBehaviour
{
    private InventoryBase inventory;
    private EquipUnequip[] unequip;
    public int itemSetValue = 20;
    public void Awake()
    {
        EventHandler.RegisterEvent<Item, IItemIdentifier, int>(gameObject, "OnItemUseConsumableItemIdentifier", OnItemUseConsumableItemIdentifier);
        inventory = gameObject.GetComponent<InventoryBase>();
    }
    private void Start()
    {
        unequip = gameObject.GetComponent<UltimateCharacterLocomotion>().GetAbilities<EquipUnequip>();
    }

    private void OnItemUseConsumableItemIdentifier(Item item, IItemIdentifier identifier, int amount)
    {
        if (item.ToString() == "SpearShootable (Opsive.UltimateCharacterController.Items.Item)" && amount == 0) //check if this is the shootable item
        {


            IUsableItem useable = item as IUsableItem;
            useable.RemoveConsumableItemIdentifierAmount();
            for (int i = 0; i < unequip.Length; ++i) //if this item is used unequip it
            {
                if (unequip[i].ItemSetCategoryIndex == 0)
                {
                    print("Try unequip   " + unequip[i].ItemSetCategoryIndex.ToString());
                    unequip[i].StartEquipUnequip(itemSetValue, true, false);

                }
            }
        }
    }
    public void Destroy()
    {
        EventHandler.RegisterEvent<Item, IItemIdentifier, int>(gameObject, "OnItemUseConsumableItemIdentifier", OnItemUseConsumableItemIdentifier);
    }


}


At the moment, I'm getting and error from this line
Code:
            useable.RemoveConsumableItemIdentifierAmount();

NullReferenceException: Object reference not set to an instance of an object
VSUnequipOnSlotEmpty.OnItemUseConsumableItemIdentifier (Opsive.UltimateCharacterController.Items.Item item, Opsive.Shared.Inventory.IItemIdentifier identifier, System.Int32 amount) (at Assets/VSUnequipOnSlotEmpty.cs:35)
Opsive.Shared.Events.InvokableAction`3[T1,T2,T3].Invoke (T1 arg1, T2 arg2, T3 arg3) (at <fa7bae0bde914e57874fdb6999909243>:0)
Opsive.Shared.Events.EventHandler.ExecuteEvent[T1,T2,T3] (System.Object obj, System.String eventName, T1 arg1, T2 arg2, T3 arg3) (at <fa7bae0bde914e57874fdb6999909243>:0)
Opsive.UltimateCharacterController.Items.Actions.ShootableWeapon.set_ClipRemaining (System.Int32 value) (at Assets/Opsive/UltimateCharacterController/Scripts/Items/Actions/ShootableWeapon.cs:367)
Opsive.UltimateCharacterController.Items.Actions.ShootableWeapon.Fire (System.Single strength) (at Assets/Opsive/UltimateCharacterController/Scripts/Items/Actions/ShootableWeapon.cs:751)
Opsive.UltimateCharacterController.Items.Actions.ShootableWeapon.TryStopItemUse () (at Assets/Opsive/UltimateCharacterController/Scripts/Items/Actions/ShootableWeapon.cs:1194)
Opsive.UltimateCharacterController.Character.Abilities.Items.Use.CanStopAbility () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/Abilities/Items/Use.cs:823)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion.TryStopAbility (Opsive.UltimateCharacterController.Character.Abilities.Ability ability, System.Boolean force) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1419)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion.TryStopAbility (Opsive.UltimateCharacterController.Character.Abilities.Ability ability) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotion.cs:1401)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.TryStopAbility (Opsive.UltimateCharacterController.Character.Abilities.Ability ability) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:245)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.UpdateAbilityInput (Opsive.UltimateCharacterController.Character.Abilities.Ability[] abilities) (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:122)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.UpdateAbilityInput () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:99)
Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotionHandler.Update () (at Assets/Opsive/UltimateCharacterController/Scripts/Character/UltimateCharacterLocomotionHandler.cs:73)

Thank you
 
Instead of this:

IUsableItem useable = item as IUsableItem;

You should first get all the item's ItemActions, then iterate through those to find the one you're looking for. The script on that page I linked does this.

C#:
            var item = inventory.GetActiveItem(i);
            if (item != null) {
                Debug.Log("Inventory Amount: " + inventory.GetItemIdentifierAmount(item.ItemIdentifier));
                // A single item can have multiple Item Actions.
                var itemActions = item.ItemActions;
                for (int j = 0; j < itemActions.Length; ++j) {
                    var usableItem = itemActions[j] as IUsableItem;
                    if (usableItem != null) {
                        var consumableItemIdentifier = usableItem.GetConsumableItemIdentifier();
                        if (consumableItemIdentifier != null) {
                            // The loaded amount is retrived from the UsableItem and hte unloaded amount is retrieved from the inventory.
                            Debug.Log("Consuambe Loaded Amount: " + usableItem.GetConsumableItemIdentifierAmount());
                            Debug.Log("Consuambe Inventory Amount: " + inventory.GetItemIdentifierAmount(consumableItemIdentifier));
                        }
                    }
                }
            }
 
Top