Different ammunition on one weapon

Sangemdoko

Moderator
Staff member
Could you confirm whether you are using the the Opsive Character Controller or not? If you do I'll move this thread to the UCC/UIS integration category.

If you are using the Character Controller you'll want to change the Ammo ItemDefinition both on the AmmoData attribute and the Item Shootable Weapon component.

Here is a snippet from one of my side projects it might help you go in the right direction. It is an Item Action that set a new ammo to the currently equipped item. It requires 2 attributes on the Main weapon: "AmmoCategory"<ItemCategory> and "AmmoData"<AmmoData>. The ammo Item requires 1 attribute: "Prefab"<GameObject>.
With this information the Item Action can check if the selected ammo can be set on this weapon, and can swap out the projectile prefab on the ShootableWeapon component:

Code:
using System;
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Integrations.UltimateInventorySystem;
using Opsive.UltimateCharacterController.Items.Actions;
using Opsive.UltimateInventorySystem.Core;
using Opsive.UltimateInventorySystem.Core.AttributeSystem;
using Opsive.UltimateInventorySystem.Core.DataStructures;
using Opsive.UltimateInventorySystem.ItemActions;
using UnityEngine;
using ItemAction = Opsive.UltimateInventorySystem.ItemActions.ItemAction;
/// <summary>
/// This action is used to swap the projectile used by a weapon using another ammo item.
/// </summary>
[Serializable]
public class SetShootableWeaponProjectile : ItemAction
{
    [Tooltip("Item Collection to check for the weapon")]
    [SerializeField] protected string m_ItemCollectionName = "Equippable Slots";
    [Tooltip("The shootable weapon category.")]
    [SerializeField] protected DynamicItemCategory m_ShootableWeaponCategory;
    [Tooltip("The projectile category.")]
    [SerializeField] protected string m_AmmoCategoryAttribute = "AmmoCategory";
    [Tooltip("The projectile attribute name.")]
    [SerializeField] protected string m_ProjectileAttributeName = "Prefab";
    [Tooltip("The ammo data attribute name.")]
    [SerializeField] protected string m_AmmoDataAttributeName = "AmmoData";
    protected Item m_SelectedWeapon;
    
    /// <summary>
    /// Default constructor.
    /// </summary>
    public SetShootableWeaponProjectile()
    {
        m_Name = "Set Projectile";
    }
    /// <summary>
    /// Returns true if the item action be invoked.
    /// </summary>
    /// <param name="itemInfo">The item.</param>
    /// <param name="itemUser">The inventory user.</param>
    /// <returns>True if it can be invoked.</returns>
    protected override bool CanInvokeInternal(ItemInfo itemInfo, ItemUser itemUser)
    {
        if (itemInfo.Item == null) {
            return false;
        }
        var characterLocomotion = itemUser.gameObject.GetCachedComponent<UltimateCharacterLocomotion>();
        if (characterLocomotion != null && !characterLocomotion.Alive) {
            return false;
        }
        var bridge = characterLocomotion.gameObject.GetCachedComponent<CharacterInventoryBridge>();
        if (bridge == null) {
            return false;
        }
    
        m_SelectedWeapon = GetSelectedWeapon(bridge);
        if (m_SelectedWeapon == null) {
            return false;
        }
        var ammoCategory = m_SelectedWeapon.GetAttribute<Attribute<ItemCategory>>(m_AmmoCategoryAttribute).GetValue();
        if (ammoCategory != null && ammoCategory.InherentlyContains(itemInfo.Item) == false) {
            return false;
        }
        return true;
    }
    /// <summary>
    /// Move an item from one collection to another.
    /// </summary>
    /// <param name="itemInfo">The item info.</param>
    protected override void InvokeActionInternal(ItemInfo itemInfo, ItemUser itemUser)
    {
        var characterLocomotion = itemUser.gameObject.GetCachedComponent<UltimateCharacterLocomotion>();
        var bridge = characterLocomotion.gameObject.GetCachedComponent<CharacterInventoryBridge>();
        
        var shootableItem = m_SelectedWeapon;
        var shootableCharacterItem = bridge.GetCharacterItem(shootableItem);
        var shootableWeapon = shootableCharacterItem?.gameObject.GetCachedComponent<ShootableWeapon>();
        if (shootableWeapon != null) {
            shootableWeapon.Unequip();
            var projectilePrefabAttribute = itemInfo.Item.GetAttribute<Attribute<GameObject>>(m_ProjectileAttributeName);
            if (projectilePrefabAttribute != null) {
                shootableWeapon.Projectile = projectilePrefabAttribute.GetValue();
            }
            //Change ammo
            shootableWeapon.SetConsumableItemIdentifier(itemInfo.Item);
        }
        
        
        var ammoDataAttribute = shootableItem.GetAttribute<Attribute<AmmoData>>(m_AmmoDataAttributeName);
        if (ammoDataAttribute != null) {
            ammoDataAttribute.SetOverrideValue(new AmmoData(itemInfo.Item.ItemDefinition, shootableWeapon.ClipSize, shootableWeapon.ClipRemaining));
        }
        if (shootableWeapon != null) {
            shootableWeapon.Equip();
            shootableWeapon.ReloadItem(true);
        }
        //No need to update the cache since the items did not change.
        bridge.Inventory.UpdateInventory(false);
    }
    public Item GetSelectedWeapon(CharacterInventoryBridge bridge)
    {
        var itemCollection = bridge.Inventory.GetItemCollection(m_ItemCollectionName);
        var items = itemCollection.GetAllItemStacks();
        for (int i = 0; i < items.Count; i++) {
            if(items[i] == null){ continue; }
            var selectedWeapon = items[i].Item;
            
            if (selectedWeapon == null) { continue; }
            if (m_ShootableWeaponCategory.Value.InherentlyContains(selectedWeapon)
                && selectedWeapon.HasAttribute(m_AmmoDataAttributeName)
                && selectedWeapon.HasAttribute(m_AmmoCategoryAttribute)) {
                return selectedWeapon;
            }
        }
        return null;
    }
    public bool TryGetAmmoData(Item selectedWeapon, out AmmoData ammoData)
    {
        var ammoDataAttribute = selectedWeapon.GetAttribute<Attribute<AmmoData>>(m_AmmoDataAttributeName);
        if (ammoDataAttribute == null) {
            ammoData = AmmoData.None;
            return false;
        }
        ammoData = ammoDataAttribute.GetValue();
        return true;
    }
}

If you aren't using the Character controller integration, you can still use the code above as a guiding point on how you can design your own ammo swapper item action.
I hope that helps
 

Sangemdoko

Moderator
Staff member
Sorry I wasn't clear, This is a UIS ItemAction. You can learn more about UIS ItemActions in the UIS documentation and video tutorials.

This UIS ItemAction is used in the UI to switch the ammo item on the currently equipped item. The code above is not meant to be used as is, but you can inspire yourself from it to make your own custom ItemAction (or custom function, it doesn't have to be an ItemAction if you don't need it to be).
 
Sorry I wasn't clear, This is a UIS ItemAction. You can learn more about UIS ItemActions in the UIS documentation and video tutorials.

This UIS ItemAction is used in the UI to switch the ammo item on the currently equipped item. The code above is not meant to be used as is, but you can inspire yourself from it to make your own custom ItemAction (or custom function, it doesn't have to be an ItemAction if you don't need it to be).
Thanks, it is work.
 
Last edited:
Hi, @Sangemdoko.

When I changed ammunition, their number in my inventory began to increase. Maybe I missed something.
The following worked for me:

123.png

private void RemoveClipRemainingAmmoToInventory() =>
m_Inventory.Pickup(m_ConsumableItemIdentifier, ClipRemaining, -1, false, false,
false);
 
Top