0

Currently working on a base RPG system, and I've run into an error with a method. The method is meant to add an item (Class within the code) and an optional amount to the players inventory (An Item[] array).

This is the code for the item class:

public class Item

{
    public string Name;
    public int quantity;
    public int maxstack;

    public int[] stats = new int[5];

    public Item(string name, int Amount = 1, int MaxStack = 10, int ATK = 0, 
    int DEF = 0, int MAT = 0, int MDF = 0, int SPD = 0)
    {
        Name = name;
        quantity = Amount;
        maxstack = MaxStack;
        stats[0] = ATK;
        stats[1] = DEF;
        stats[2] = MAT;
        stats[3] = MDF;
        stats[4] = SPD;
    }
}

The key variables are "quantity" and "maxstack."

Now, the issue comes when adding an item to the players inventory, regarding these variables. The method, when adding an Item to the inventory, searches for both an empty slot within the inventory and any stacks of the same item using Array.IndexOf();

This is the code for the AddItem() method:

public void AddItem(Item item, int Amount = 1)
{
    for (int i = Amount; i > 0; i--)
    {
        int ItemIndex = Array.IndexOf(inv, item); // Searches for a matching item
        int EmptySlot = Array.IndexOf(inv, null); // Searches for an empty slot

        ItemCheck:
        if (ItemIndex != -1) // ItemIndex will equal -1 if no matching item was found
        {
            if (inv[ItemIndex].quantity >= inv[ItemIndex].maxstack) // Is the quantity/stack of the found item equal to its maximum stackable value?
            {
                ItemIndex = Array.IndexOf(inv, item, ItemIndex + 1); // If yes, search for another index.
                goto ItemCheck;
            } else {
            inv[ItemIndex].quantity++; // If the stack hasn't reached its max, increase it by one.
            }
        }
        else
        {
            inv[EmptySlot] = item; // If no matching item was found, use an empty slot to create a new stack.
            inv[EmptySlot].quantity = 1;
        }
    }
}

Now, lets say I create an item called "stick" and it can only stack a maximum of 3. When running AddItem(stick, 3) and listing the quantity of each stack, the console returns

Stick x1
Stick x1

Can anyone help me? Why is my code turning the stack back into a quantity of 1?

EDIT:

Adding 1, 2 or 3 sticks returns the correct quantity, but only adding more sticks once a stack has reached its max throws the wrong result.

EDIT:

Adding 6 sticks returns 2 stacks with 3 items in each. Adding 7 sticks returns 3 stacks with 1 item in each.

5
  • so, what's inv? Commented Apr 29, 2018 at 6:57
  • 1
    I'm going to take wild guess and say it's probably not working because Array.IndexOf found no item in the array that is equivalent in value to whatever Item object you're passing to the function. Commented Apr 29, 2018 at 7:00
  • 2
    stares at the goto ...... you know the SO people want us to be nice to new people.... but sometimes I feel it's challenging :) Commented Apr 29, 2018 at 7:03
  • @KeithNicholas It might be better to provide a constructive an informative reason as to why goto enables bad code flow; we know it, but not everybody does. Commented Apr 29, 2018 at 7:05
  • oh I know.... I know the problem. Commented Apr 29, 2018 at 7:08

2 Answers 2

3

The biggest problem here is you use the item to store the quantity... but the item is used in multiple places in your inventory. So when you change the quantity back to 1, you are changing it for every slot that the item exists in in the inventory.

ie, you don't have copies of the item, you have the same object multiple times.

Many ways you can solve this, but perhaps you should make a new class called a InventorySlot and put the quantity in there.

public class InventorySlot
{
   public Item Item {get; set;}
   public int Quantity {get; set;}
}

now you players inventory is an array of InventorySlots... like so given you have something like this in your player...

 public InventorySlot[] inv = new InventorySlot[5];

then

public void AddItem(Item item, int amount = 1)
{
    var slot = inv.FirstOrDefault(s => s?.Item == item && s.Quantity < item.maxstack);
    if (slot != null)
    {
        slot.Quantity++;
    }
    else
    {
        slot = inv.FirstOrDefault(s => s == null);
        if (slot != null)
        {
            slot.Item = item;
            slot.Quantity = 1;
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Completely didn't think about how the quantity would change the global item's value. Thank you!
Now the function seems to be throwing an error with this line: var slot = inv.FirstOrDefault(s => s.Item == item && s.Quantity < item.maxstack); Its throwing 'System.NullReferenceException: 'Object reference not set to an instance of an object.' s was null.
oh, yeah..... I'll adjust, there is now a ? mark after s, which means if s is null it won't try to get the Item, it will just evaluate to null
1

I don't understand why would you need to add an item to an array, when the standard library already provides List<T>, which defines methods such as Add, Remove, RemoveAt, Insert and IndexOf.

Example:

List<Item> yourList = new List<Item>(); // Create an empty list
/* Or
 * List<Item> youtList = new List<Item>()
 * {
 *     new Item(),
 *     new Item() // etc
 * }
 */
yourList.Add(new Item()); // Add an item 
yourList.Insert(0, new Item()); // Insert an item to the 0 index
yourList.Remove(yourItem); // Remove an item by reference
yourList.RemoveAt(0); // Remove an item by its position in the list
Item[] yourArray = yourList.ToArray(); // Create an array with the elements in the list

Refer to the docs.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.