I
This is tricky because we have to look through three different classes to see what is going on.
We’ll start with the DragItem, as there is only one way that an Action will get added to the Action Store, via dragging from an InventorySlotUI, or another ActionSlotUI into the ActionSlotUI.
The important part of DragItem is in DropIntoContainer(), here’s the bit we’re interested in:
if (destinationContainer == null || sourceContainer == null ||
destinationContainer.GetItem() == null ||
object.ReferenceEquals(destinationContainer.GetItem(), sourceContainer.GetItem()))
{
AttemptSimpleTransfer(destination);
return;
}
AttemptSwap(destinationContainer, sourceContainer);
At this point, we haven’t removed any items from either container. If we determine that the item being dragged to the slot is the same item as the one in the slot then we attempt a simple transfer. We also attempt a simple transfer if there is nothing in the destination container.
If this lengthy check fails, then both the source container and the destination container contain items (but not identical ones) and then we head to AttemptSwap. As far as AttemptSwap is concerned, the only issue is whether the item is an ActionItem. If it is, then if it’s stackable, the slot will take as many as you want (unless you actually put a limit in MaxAcceptable).
If it’s not a swap, then we head to AttemptSimpleTransfer:
private bool AttemptSimpleTransfer(IDragDestination<T> destination)
{
var draggingItem = source.GetItem();
var draggingNumber = source.GetNumber();
var acceptable = destination.MaxAcceptable(draggingItem);
var toTransfer = Mathf.Min(acceptable, draggingNumber);
if (toTransfer > 0)
{
source.RemoveItems(toTransfer);
destination.AddItems(draggingItem, toTransfer);
return false;
}
return true;
}
So here, we first find out how many we have to transfer, and we find out how many the destination will accept. This is the point where we can restrict the number that are transferred. (note that this will also happen in the AttemptSwap, so the same logic I’m about to show you will apply).
Now let’s suppose that we’ve decided that no stack in the ActionStore should be larger than 10. We need to find out how many items are acceptable, so we ask the destination for MaxAcceptable.
So ActionSlotUI.MaxAcceptable() passes the buck:
public int MaxAcceptable(InventoryItem item)
{
return store.MaxAcceptable(item, index);
}
Since ActionSlotUI has passed the buck, we have to head to the ActionStore.MaxAcceptable
public int MaxAcceptable(InventoryItem item, int index)
{
var actionItem = item as ActionItem;
if (!actionItem) return 0;
if (dockedItems.ContainsKey(index) && !object.ReferenceEquals(item, dockedItems[index].item))
{
return 0;
}
if (actionItem.isConsumable())
{
return int.MaxValue;
}
if (dockedItems.ContainsKey(index))
{
return 0;
}
return 1;
}
Here, we run a few simple checks:
If it’s not an ActionItem, then reject it.
If it’s not the SAME ActionItem as the one in the slot, return 0 (note that this case should be ruled out by the check in DragItem, but it’s still a good check in case you create another way to add items)
If it’s consumable, then it returns in.MaxValue. This is actually where you would set a custom MaxAcceptable. Assuming you have an int maxStack, say it’s 10…
if (actionItem.isConsumable())
{
if (dockedItems.ContainsKey(index))
{
return Mathf.Max(0, maxStack - dockedItems[index].number);
}
return int.MaxValue;
}
This would limit all stacks in ActionStore to maxStack.
You could also have a field in InventoryItem with Max Stack Size.
return Mathf.Max(0, item.MaxStackSize - dockedItems[index].number);
You’re right, it doesn’t check other slots for a copy of the item, and this would allow you to make multiple stacks of the same item. This handy fix ought to do it.
public void AddAction(InventoryItem item, int index, int number)
{
if (dockedItems.ContainsKey(index))
{
if (object.ReferenceEquals(item, dockedItems[index].item))
{
dockedItems[index].number += number;
}
}
else if (item.IsStackable() && FindExistingSlot(item) > -1)
{
AddAction(item, FindExistingSlot(item), number);
}
else
{
var slot = new DockedItemSlot();
slot.item = item as ActionItem;
slot.number = number;
dockedItems[index] = slot;
}
if (storeUpdated != null)
{
storeUpdated();
}
}
public int FindExistingSlot(InventoryItem item)
{
foreach (var pair in dockedItems)
{
if (object.ReferenceEquals(item, pair.Value.item)) return pair.Key;
}
return -1;
}