Saving weapons with randomized stats

So I’m just experimenting with creating an RPG game and want to make weapons that have random modifiers.

I would probably go about this by adding a folder called “Modifiers” into the tool that holds intvalues with names such as “LifeSteal” with the value representing the percent to be stolen.

My problem lies with how I would save these items. I thought about it and only came to the conclusion that I could do it like this:

local inventory = game.Players:FindFirstChild("Inventory")
local invData = {}

for i, item in ipairs(inventory) do
   table.insert(invData, item.Name)
   for i, modif in ipairs(item:FindFirstChild("Modifiers"):GetChildren()) do
      table.insert(invData, modif.Name)
      table.insert(invData, modif.Value)
   end
end

The reason I say this is a problem is because it just seems inefficient to me, but I’m still pretty new to scripting so I wanted to ask if there is a better way to do this because if not, reading the data seems like it be a pretty extensive task because I’d have to check for the item name, and for each modifier I’d have to make sure it parented to the tool.
Ex:

for i, item in ipairs(invData) do
   if itemStorage[item] then
   -- clone item to inv/backpack
   elseif itemModifiers[item] then
      local num = i - 1
         if itemStorage:FindFirstChild(invData[num]) then
         -- clone modifier to the last item cloned
         else
            repeat
               num = num - 1
            until itemStorage:FindFirstChild(invData[num]) ~= nil
            -- clone modifier to last item cloned using num
         end
   else
      -- this would be if "item" is a value and would just be assigned to the last modifier
   end
end

Is there any better way to accomplish this?

1 Like

Have you considered using attributes? It seems like if you’re already traversing through a folder/inventory of instances you might as well.

2 Likes

You should use dictionaries, they work similar to arrays but you can access values via what’s know as “key”.
Dictionaries are slightly more complicated to work in loops. But you will be able to know easier where holds the stats. The code can be done like this:

for i, item in ipairs(inventory) do
   invData[item.Name]={} -- invData now acts as a dictionary
   local itemData=invData[item.Name] -- referring dictionary, this will not clone
   for i, modif in ipairs(item:FindFirstChild("Modifiers"):GetChildren()) do
      -- each key in itemData is a modifier name
      itemData[modif.Name]=modif.Value
   end
end
-- you have to use pairs() instead of ipairs() for dictionaries
for item, modifiers in pairs(invData) do
   -- because now you know that every item is an item, you just have to clone it then iterate the modifiers
   for name, value in pairs(modifiers) do
      -- clone modifier to item
   end
end

I’ve considered using attributes and I didn’t think I wanted to at first, but now that you said it it makes more sense to use attributes instead of having a folder that way I can just use :SetAttribute() and not have to worry about parenting the modifier. I guess I didn’t really think enough about that, thanks

1 Like

Also attributes have less of a performance impact than valuebases since an attribute is just assigning a value to an instance similar to properties whereas value objects take up more memory since it contains many properties and functions derived from instances.

Also if you’re working with arbitrary properties (eg. different weapons have different property names), instance:GetAttributes() returns a dictionary which can be saved to data store as-is (assuming you’re using bools, strings and numbers only).

2 Likes

I have no experience using dictionaries so I’m a bit confused with the part for modifiers

Does this make a dictionary for every item and save them all into invData?

1 Like

Yes. Without having to make an extremely long array.

1 Like

So if I were to combine what all 3 of you said so far like so;

Saving:

for i, item in ipairs(inventory:GetChildren()) do
   invData[item.Name] = {}
   local itemData = invData[item.Name]
   for i, modif in ipairs(item:GetAttributes()) do
      itemData[modif.Name] = modif.Value
   end
end

Reading:

for item, modifiers in pairs(invData) do
   itemStorage[item]:Clone().Parent = inv
   for name, value in pairs(modifiers) do
      item:SetAttribute(name, value)
   end
end

This would be the final solution, correct?
Also @HMgamingTheSecondary does the line

invData[item.Name] = {}

insert the dictionaries into the table or would I still have to do that.

invData[item.Name] was an empty table then, so it can be used as either array or dictionary. (which later in the code it has been used as a dictionary)

modif.Value will be nil assuming modif is a string. You also don’t have to iterate through all the attributes:

for i, item in ipairs(inventory:GetChildren()) do
    invData[item.Name] = item:GetAttributes()
end

Thank you! That cleared up a lot of my confusion about dictionaries and I don’t plan on using any strings, only numbers so it should be fine for what I’m doing.

1 Like

Also, if it’s possible to get multiple of the same item, do not use the item’s name as the index, it will cause one item to be overridden by another, only a single item of each type will load.

Instead, try something like so:

local inventoryData = {}
for i, item in ipairs(inventory:GetChildren()) do
    local itemData = {}
    itemData.Name = item.Name
    itemData.Properties = item:GetAttributes()
    table.insert(inventoryData, itemData)
end

Then to reference the item in the loading script, do something like

for i,itemInfo in ipairs(loadedInventoryData) do
    local newItem = serverStorage:FindFirstChild(itemInfo.Name):Clone()
    for propertyName,propertyValue in pairs(itemInfo.Properties) do
        newItem:SetAttribute(propertyName, propertyValue)
    end
end

So with that, setting the item name by doing “itemData.Name = item.Name” allows multiple of the same item?

Also, would I add “table.insert(inventoryData, itemData)” as the last line of the first for loop?

Yeah because instead of making an array where the index is the item’s name, it makes the index a number (like a typical table).

Yes, I forgot to add that, my bad.

1 Like