RNG weighted system

The title basically sums it up im trying to remake this

but i have no idea on how to do it

this is what ive tried local function calculateTotalWeight()
local totalWeight = 0
for _, petWeights in pairs(PetData.Skins) do
for _, weight in pairs(petWeights) do
totalWeight = totalWeight + (1 / weight)
end
end
return totalWeight
end
function PetData.rollPet()
local totalWeight = calculateTotalWeight()
local roll = math.random() * totalWeight
local cumulativeWeight = 0

for petName, petWeights in pairs(PetData.Skins) do
	for petType, weight in pairs(petWeights) do
		cumulativeWeight = cumulativeWeight + (1 / weight)
		if roll <= cumulativeWeight then
			return petName, petType, weight
		end
	end
end

end

2 Likes

This is the way I make mine:

local valueList = {
    {
        name = "Peanut",
        chance = "1/2",
    },
    {
        name = "Apple",
        chance = "1/14",
        -- Add more values here if needed
    }
}

function getRandomValue()

    -- Calculate the total weight of all values
    local totalWeight = 0
    for _, value in ipairs(valueList) do
        totalWeight = totalWeight + value.chance
    end

    -- If totalWeight is 0 or less, fall back to a guaranteed rune
    if totalWeight <= 0 then
        warn("Total weight is zero or negative! Returning the first value as fallback.")
        return valueList[1]
    end

    -- Generate a random weight
    local randomWeight = math.random() * totalWeight
    local cumulativeWeight = 0

    -- Iterate through the values and find the selected one
    for _, value in ipairs(valueList) do
        cumulativeWeight = cumulativeWeight + value.chance
        if randomWeight <= cumulativeWeight then
            return value
        end
    end

    -- Fallback: Return the first rune if all else fails
    warn("Random selection failed; returning the first rune as fallback.")
    return valueList[1]
end


You would also need to set a math.randomseed() to keep it more random.

If you would like to add a luck multiplier. I would create a new table when I’m calculating the total weight on all values and add a baseline like 1 (In this case it would be 100%)

Later iterate through the table with the adjustedChances instead of value list to find the selected one

Having a baseline we can check it like this:

        local adjustedChance = value.chance * chanceMultiplier

        if adjustedChance >= baselineProbability then
            adjustedChance = value.chance / chanceMultiplier
        end

This way it would decrease the chance to get the more common ones, while increasing the chance for the rarer values.

ForeverHD has a fantastic example of this: Creating a Crate/Spin System

Hopefully, It will provide a bit more help and understanding of how something like this would work!

2 Likes

Workspace.Script:17: attempt to perform arithmetic (add) on number and string I got this error when i tried your method

The chance’s shouldn’t be a string. My bad.

It should look like this:

local valueList = {
    {
        name = "Peanut",
        chance = 1/2,
    },
    {
        name = "Apple",
        chance = 1/14,
        -- Add more values here if needed
    }
}