Yes, something like our Purse(), but holding arrows/ammo instead of coins…
I would start with a subclass of InventoryItem to represent the ammunition…
using GameDevTV.Inventories;
using UnityEngine;
namespace RPG.Inventories
{
[CreateAssetMenu(fileName = "Ammunition", menuName = "RPG/Ammunition/New Ammunition", order = 0)]
public class AmmunitionItem : InventoryItem
{
}
}
It doesn’t have to do much, it’s just to differentiate it from other InventoryItems you don’t want in your Quiver…
Your WeaponConfig would then have a reference to the AmmunitionItem which can be checked with Fighter.
Then you’ll need a Quiver component. I’ve fleshed out a basic quiver component here:
using GameDevTV.Inventories;
using GameDevTV.Saving;
using Newtonsoft.Json.Linq;
using UnityEngine;
namespace RPG.Inventories
{
public class Quiver : MonoBehaviour, IJsonSaveable
{
public event System.Action quiverUpdated;
private AmmunitionItem currentAmmunition=null;
private int amount = 0;
public bool HasSufficientAmmunition(AmmunitionItem requiredAmmunition, int requiredAmount = 1)
{
return currentAmmunition != null && (requiredAmmunition == currentAmmunition) && amount >= requiredAmount;
}
public void SpendAmmo(int amountToSpend)
{
amount -= amountToSpend;
if (amount <= 0)
{
currentAmmunition =null;
amount = 0;
}
quiverUpdated?.Invoke();
}
public AmmunitionItem GetItem() => currentAmmunition;
public int GetAmount() => amount;
public void RemoveAmmunition(int removeAmount = -1)
{
if (removeAmount < 0) removeAmount = amount;
amount -= removeAmount;
if (amount <= 0)
{
currentAmmunition = null;
amount = 0;
}
quiverUpdated?.Invoke();
}
public void AddAmmunition(AmmunitionItem item, int number)
{
currentAmmunition = item;
amount = number;
quiverUpdated?.Invoke();
}
public JToken CaptureAsJToken()
{
JObject state = new JObject
{
[nameof(currentAmmunition)] = currentAmmunition != null ? currentAmmunition.GetItemID() : "",
[nameof(amount)] = amount
};
return state;
}
public void RestoreFromJToken(JToken state)
{
currentAmmunition = null;
amount = 0;
if (state is JObject stateDict)
{
if (stateDict.TryGetValue(nameof(currentAmmunition), out JToken token))
{
var item = InventoryItem.GetFromID(token.ToString());
if (item is AmmunitionItem ammunitionItem)
{
currentAmmunition = ammunitionItem;
if (stateDict.TryGetValue(nameof(amount), out JToken amountToken) &&
int.TryParse(amountToken.ToString(), out int number))
{
amount = number;
}
}
}
}
quiverUpdated?.Invoke();
}
public int SavePriority()
{
return 1;
}
}
}
In Fighter, before setting the animator trigger to attack, you’ll need to check to see if the config is a projectile, if it has an ammo requirement, and if there is sufficient ammo of that type in the quiver:
private void AttackBehaviour()
{
transform.LookAt(target.transform);
GetComponent<Mover>().MoveTo(transform.position, 0);
if (timeSinceLastAttack > timeBetweenAttacks && CheckForProjectileAndSufficientAmmo())
{
// This will trigger the Hit() event.
TriggerAttack();
timeSinceLastAttack = 0;
}
}
bool CheckForProjectileAndSufficientAmmo()
{
if (!currentWeaponConfig.HasProjectile()) return true;
if (currentWeaponConfig.GetAmmunitionItem() == null) return true; //Edited
if (GetComponent<Quiver>().HasSufficientAmmunition(currentWeaponConfig.GetAmmunitionItem())) return true;
return false;
}
And when we spawn the projectile, we’ll need to deduct one from the Quiver
if (currentWeaponConfig.HasProjectile())
{
if (currentWeaponConfig.GetAmmunitionItem())
{
GetComponent<Quiver>().SpendAmmo(1);
}
currentWeaponConfig.LaunchProjectile(rightHandTransform, leftHandTransform, target, gameObject, damage);
}
All that’s left at this point is the EquipmentUI…
You’ll need a new QuiverItemUI, which will be modelled after EquipSlotUI, but will be quite a bit stripped down…
The class will need a reference to the player’s Quiver (you could use Inventory.GetPlayerInventory().GetComponent<Quiver>()
; to get this…
As the quiver is just one slot, you don’t need to worry about a slot, so the methods will simply have to call methods on Quiver, for example, to get the item, simply use quiver.GetItem() (or quiver.GetNumber())…
You’ll need to implement the interfaces that we use in InventorySlotUI and EquipSlotUI to allow dragging/dropping as well as tooltips…
In the editor, you’ll need to build a prefab with a QuiverItemUI component. You might start by duplicating an EquipmentSlot prefab and replacing the EquipSlotUI with QuiverItemUI. Once this is completed, you can add the QuiverItemUI to the Equipment canvas.
So that’s your challenge