Integrating with ActionStore

A few questions popped up here

  1. We have this MaxAcceptable method but we don’t seem to use it when adding items. It looks like AddAction() can cause an overflow because it doesn’t check MaxAcceptable. Bug or am I misunderstanding what we’re trying to do with MaxAcceptable?

  2. I noticed AddAction does not check if the item already exists in the ActionStore. We only check if it’s at the right index. Is this a bug or intended as part of game play to be able to have multiple of the same stackable item in the Action Store?

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;
        }

Yup. I’m not surprised there’s a lot of complexity here.

This is just a thought experiment for now but…

…my idea to simplify this was to most or all of the ActionStore functionality and have the ActionSlotUI just point to an item within the Inventory. I would let the inventory handle the count for me. Maybe might still need ActionStore as an interface for PlayerController? Don’t know - I didn’t think that through yet.

My ActionSlotUI really I think would just be a convenience UI for something that’s in the inventory.

  1. to show me how many I have
  2. to receive clicks
  3. to allow me to configure what is in each slot

Again just a thought experiment for now as I’m still experimenting with different interaction mechanics in my own creation. While the game I want to create won’t have the same mechanics, this course is helpful to see where the complexity lies.

That’s really what’s happening already. Most of the methods in ActionSlotUI are to fulfill the interface contracts for dragging. The DragItem script doesn’t know or care about ActionStore, to it, the containers are the ActionSlotUI, EquipSlotUI and InventorySlotUI. The fulfillment methods are all pretty much passthroughs to the underlying store.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms