How do i make a chance system?

I want to make a chance system with selected stuff in a table:

local AllowedEnemies = {
	["EnemyOne"] = ChanceNumber;
	["EnemyTwo"] = ChanceNumber;
	}

For example, the selected table item will be printed, but i don’t know how can i do that. I tried to duplicate the tables items, so there will be a bigger chance with the duplicated item, but that looks like a bad practice, could you help me? Thanks for reading :+1: :123:

19 Likes

You can use the math.random function depending on if you mean what I am thinking, however is it randomly making the chance or is there a pre-made chance value?

Is there a reason you think duplicated items are “bad practice?” I personally use duplicated items and do not really have any trouble. The memory usage is not bad either, but I could see a problem where if you had around 100000 “weight” it would be pretty bad (making 100000 instances of the item).

One method could be to put all of your items in an array and to sort the array such that items with rarer chance are at the beginning and the more common items at the top. Then generate a random number from [0, 1) and compare whether that number is equal to or under each item.

Some example code for this concept:

local loot = {
    ["cheezits"] = .1,
    ["super cat"] = .37,
    ["doge :3"] = 1
}

local sortedLoot = {}

for name, chance in pairs(loot) do
    sortedLoot[#sortedLoot + 1] = {
        name = name,
        chance = chance
    }
end

table.sort(sortedLoot, function(itemA, itemB)
    return itemA.chance < itemB.chance
end)

local function getRandomItem()
    local random = math.random()

    for i, item in pairs(sortedLoot) do
        if random <= item.chance then
            return item.name
        end
    end
end

for i = 1, 100 do
    local itemName = getRandomItem()

    print(itemName)
end

There is a flaw here though, where you require at least one item to be a 1 (alternatively be the max number that can be generated from your math.random(x, y))

5 Likes

Hey, I’ve been interested in this for a while so I did some research and found a solution I really like, and I hope it helps

It’s weight based, not percentage based

-- your list of items, I tend to have these in a seperate module
local items = {
	{Name = "Iron Sword"},
	{Name = "Iron"},
	{Name = "Gold"}
}

--[[ 
	a loot table, it's wise to keep these seperate from your item list as it allows you to make
	multiple loot tables
	
	needs to be linear, greatest to least, and remember it's based on weight not percentages
--]]
local lootTable = {
	{Item = items[2], Weight = 100}, -- each one of these is an entry
	{Item = items[3], Weight = 50},
	{Item = items[1], Weight = 20}
}

-- used in weight random number generation
local function returnSumOfWeight(lootTable)
	local sum = 0
	for _, entry in ipairs(lootTable) do
		sum = sum + entry.Weight
	end
	return sum
end

-- returns a random item from given lootTable
local function getRandomItem(lootTable)
	-- returns a random number based on total weight of given lootTable
	local randomNumber = math.random(returnSumOfWeight(lootTable))
	
	for _, entry in ipairs(lootTable) do
		if  randomNumber <= entry.Weight then
			return entry.Item
		else
			randomNumber = randomNumber - entry.Weight
		end
	end
end

-- just for testing, mess around with it how you like
for i = 1, 100 do
	local item = getRandomItem(lootTable)
	print(item.Name)
end
Output Examples

when iron is 1000 weight

image

when it’s 100 (closer to the other weights so more even results but iron is still most common)

bonus minecraft example because why not

I did research for a while but found this most helpful

it’s in C# but he does some explaining in english so it will help out in the understanding of a weighted system (I don’t know C# myself, that’s why I can vouch)

46 Likes

@j8cksxn - It’s a pre-made chance, as you said, for example:
80% of chance that you will get killed by a door
20% of chance that you will get killed by the air.

@EpicMetatableMoment - I got a timeout error, in the line following line:

 return itemA.chance < itemB.chance

@Quoteory - As above, i got a timeout script, which by any reason, was mentioning this line:

local lootTable = {
	{Item = items[2], Weight = 100}, 
	{Item = items[3], Weight = 50},
	{Item = items[1], Weight = 20},
} --//This line

1 Like

It works fine on my side, trying adding a wait() to the bottom for loop, or reduce the 100 to 10 or 5

that may be the issue if your pc is low spec

@Conejin_Alt maybe try adding a wait(15) above the loop so you load in to play in studio before it runs, other than that I don’t know because it isn’t very intensive to run

The problem is that my pc is slow, as you said, because the other options to solve this that you gave me didn’t work.

1 Like

@Quoteory’s method is exactly what I used for loot spawning in a game – it should work perfectly fine. It’s the best way that I could find to run chance simulations for my purposes, should work fine for you.

2 Likes

I’m using this

local chance = 0

script.Parent.MouseButton1Click:Connect(function()

chance = math.random(1,100)

if chance > 1 and chance <= 10 then

print(chance) -- here you can give a player something you want, but im dont have anything so i'm use print

end

end)

it is measured in percentages or how many times it takes to knock it out?