Assign Abilities to Item Categories

almostchris

New member
I've been going through the docs and code for a couple of days now and can't seem to figure out how to tie a Use ability to an ItemCategory and not the Slot #.

I've got the Weapons, Throwables, Disposables, and Consumables categories and would like to trigger the Use ability with different input combinations:

-The Weapons category uses the default Use ability where the Fire1 key shoots and Fire2 aims.
-The Throwables works pretty much as the Grenades do in UCC except that you can only throw while aiming: Fire2 down continuous + Fire1.
-The Disposables can get thrown just like the Throwables or dropped if just the Fire1 key is pressed (think of it as random junk which shouldn't be added to inventory but can be thrown to inflict damage to enemies).
-The Consumables are basically medkits and powerups which get used with Fire1 or unequipped with Fire2.

For the most part, I've got the Use abilities working as described only when a single ability is enabled. However, if all 4 Use abilities are enabled, the first ability will always override the others regardless of which category the equipped item belongs to.

Is there a way to link abilities with Item Categories or should I disable/enable them at runtime or something?
 
The Use ability is tied to a slot and it is not aware of the category system. You could subclass the Use ability and add support for this, but built-in your only option is to enable/disable the abilities at runtime.
 
Thanks for the quick reply, Justin! I went the disable route using the state system presets. However, I can't get the ItemSetManager to equip any of the Items which don't belong to the Weapons category without losing the default Body melee attacks.

I've got the Equip/EquipNext/EquipToggle actions all set up for the appropriate categories, but they do nothing no matter if the Item is in the default loadout or being picked up at runtime. The item gets added to the inventory but only gets equipped if the current itemSet equipped in the Weapons category has both slots empty.

I've tried adding a new category called TestCat in a fresh project and assigning it to the Sword itemType, removing the sword itemType sets from the Weapons category of Nolan's ItemSetManager and adding a new set in the Melee category. When I run the scene the Sword still gets added to the Weapons category automatically for some reason but when I click on the Set in the editor the reference to the sword disappears since the categories don't match. This effectively breaks the use of the default Body itemType when EquipNext is called and only at that point the sword can be equipped by the ToggleEquip ability assigned to TestCat.

Is it possible to prevent every single ItemType from being added to the Weapons category and how can I switch between items belonging to different categories which are all assigned to Slot 0?
 
For equip issues it's best to go through this checklist to ensure everything is setup correctly:


I would start simple, get one weapon working in a single category, then slowly add more and more to it so that if something goes wrong you can focus on that aspect.
 
For equip issues it's best to go through this checklist to ensure everything is setup correctly:


I would start simple, get one weapon working in a single category, then slowly add more and more to it so that if something goes wrong you can focus on that aspect.

Just to clarify, I can get the individual weapons in the main category working without any issues. The problem I'm having is that all the weapons parented to the character's Items object automatically get added to the first category at runtime regardless of the category assigned to the ItemType. That seems like a bug in the ItemSetManager rather than an issue with my setup since even the inspector script throws an "Unable to add ItemType Sword - the ItemType category doesn't match the parent category." error.
As for the other issue, do you have any pointers on how to tell the ItemSetManager to use a specific category? I couldn't find anything in the documentation related to equipping an item from category2 while a category1 item is still equipped in the same slot.
 
The categories are defined within the Item Type Manager - you'll either want to make sure there is a (none) assigned or it is correctly assigned to the category that you are adding it to. In the demo scene the Secondary Frag Grenade is assigned to a different category and it persists within that category at runtime.

Multiple items can't be equipped within the same slot, even if there are multiple categories. You can use a new slot for the new category.
 
Well, I've spent almost a week debugging every single class related to the equip activity and as I originally suspected the bug was in the ItemSetManager. The manager would retain a cached version of m_CategoryItemSets and wouldn't update it on Awake so any new ItemType or an old ItemType assigned to a new category would just get assigned to m_CategoryItemSets[0].

Everything works as it should after I commented out the Length check in the InitializeItemCollection method.

C#:
   if (/*m_CategoryItemSets.Length == 0 &&*/ m_ItemCollection.Categories.Length > 0)
            {
                m_CategoryItemSets = new CategoryItemSet[m_ItemCollection.Categories.Length];
            }


And yeah I didn't mean I wanted to equip multiple items in the same slot simultaneously, rather unequip the ItemSet currently equipped by EquipUnequip assigned to cat1 when cat2 equip is toggled. I've managed to achieve that by extending the ToggleEquip class to listen to OnInventoryEquipItem event.

C#:
using Opsive.UltimateCharacterController.Character.Abilities;
using Opsive.UltimateCharacterController.Character.Abilities.Items;
using Opsive.UltimateCharacterController.Events;
using Opsive.UltimateCharacterController.Inventory;
using Opsive.UltimateCharacterController.Items;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// The ToggleEquipUnequip ability will automatically unequip currently equiped item if an item belonging to another category is being equipped.
/// uses the same logic as ToggleEquip for toggle and the EquipUnequip ability to do the actual equip/unequip.
/// (Requires extending the EquipUnequip class and commenting out [if (skipEquip){}] in order to ignore category priority.)
/// </summary>
[DefaultStartType(AbilityStartType.ButtonDown)]
[DefaultInputName("Toggle Item Equip")]
[AllowMultipleAbilityTypes]
public class ToggleEquipUnequip : ToggleEquip
{
    public override void Awake()
    {
        base.Awake();

        EventHandler.RegisterEvent<Item, int>(m_GameObject, "OnInventoryEquipItem", OnEquipItem);
        EventHandler.RegisterEvent<Item, float, bool, bool>(m_GameObject, "OnInventoryPickupItem", OnPickupItem);

    }

    /// <summary>
    /// An Item has been equipped. Check if it matches the CategoryId assigned to this Activity and clear itemSetIndex if it doesn't.
    /// </summary>
    /// <param name="item">The item currently being equipped by the Inventory.</param>
    void OnEquipItem(Item item, int q)
    {

        var unequip = !item.ItemType.CategoryIDMatch(m_ItemSetCategoryID);
        if (unequip)
        {
            m_EquipUnequipItemAbility.StartEquipUnequip(-1, true);
        }
    }


    /// <summary>
    /// A lazy hack to force the ToggleEquip activity to equip an ItemSet picked up at runtime which belongs to an empty category, and AutoEquip is set to None.
    /// (Requires making the m_PrevItemSetIndex protected in ToggleEquip in order to work.)
    /// </summary>
    /// <param name="item">The item that was just picked up.</param>
    void OnPickupItem(Item item, float q, bool b1, bool b2)
    {

        var matchesCategory = item.ItemType.CategoryIDMatch(m_ItemSetCategoryID);
        if (matchesCategory)
        {
            if (m_EquipUnequipItemAbility.ActiveItemSetIndex == -1 && m_PrevItemSetIndex == 0 || m_PrevItemSetIndex == -1)
            {
                var index = m_ItemSetManager.GetItemSetIndex(item, m_ItemSetCategoryIndex, false, true);
                m_PrevItemSetIndex = index;
            }
        }
    }

    public override void OnDestroy()
    {
        base.OnDestroy();
        EventHandler.UnregisterEvent<Item, int>(m_GameObject, "OnInventoryEquipItem", OnEquipItem);
        EventHandler.UnregisterEvent<Item, float, bool, bool>(m_GameObject, "OnInventoryPickupItem", OnPickupItem);

    }
}

I'm not sure if it's the proper way of doing things, but it seems to work, at least in my corner-case scenario.
Still can't figure out how to get the initial equip to work with runtime pickups when auto equip is set to none and the category contains no itemsets on awake though.
Edit: Just added a sort of workaround for the initial equip issue by setting the m_PrevItemSetIndex OnItemPickup. Would it be possible to have the m_PrevItemSetIndex access changed to protected in the next update if not at least make the InitializeItemCollection() in the ItemSetManager extendable?
 
Last edited:
Top