Evgenij Tsvetkov
Member
Hello!
How can use different ammunition on one weapon through the inventory system? Is that possible?
How can use different ammunition on one weapon through the inventory system? Is that possible?
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;
}
}
Thanks, it is work.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).