How to make a chance / percentage script

I have made my own script but somene said its inaccurate and I just want to know how to make a script that has a % chance of getting something and also for it to not only include whole numbers but decimal percentages such as 3.1,0.1,0.001

My script:


1 Like

if chosenchance == 60 or chosenchance > 32 then
The first condition of this expression is unnecessary, if chosenchance is greater than 32 then it can also be 60. The same applies for the other expressions where this logic is used.

1 Like
local chances = {
	SpeedBoost = 60;
	JumpBoost = 32;
	Regen =7;
	LowGravity = 1;

	local x =,100)
	print(x) -- or math.round(x)
	if x >= chances.LowGravity and x < chances.Regen then
	elseif x>= chances.Regen and x < chances.JumpBoost then
	elseif x>= chances.JumpBoost and x<chances.SpeedBoost then
	elseif x>= chances.SpeedBoost then

Something like this?

1 Like

what is the,100)

Here’s another idea you can play around with. Rather than relying on fixed percents for the value in the chances dict, it treats those numbers as ratios. So, if there were 3 items in the list that had equal probability, then they would each have the same value. In your given chances dict, the values as ratios are 60:32:7:1, since the total is 100, then the chances of ea are 60/100, 32/100, 7/100, 1/100 or 60%, 32%, etc. You don’t need the values in the chances dict to be percents (portions of 100) though; would work fine with other ratios like 1:1:1, which would become 1/3, 1/3, 1/3 or 33%, 33%, 33% as the odds.

Can think of this code as working like a wheel. Each item in your chances dictionary is a wedge on the wheel and its size is proportional to the odds that it will be picked. Something like this if the ‘wheel’ were linear (letters rep ea item in the list).
0 [L][..R..][........J........][....................S....................] 100
when a rand number is picked between the start and end values (0 and 100 in this case), where it falls determines which item is selected. Since ‘S’ , here, takes up the most space in that range, it is the most likely to be picked.

local CHANCES = {
	SpeedBoost = 60,
	JumpBoost = 32,
	Regen = 7,
	LowGravity = 1,
local sumOfChances	-- could be pre-calculated and stored in constant

-- uses const CHANCES dict
local function getSumOfChances()
	local sum = 0
	for k,v in pairs(CHANCES) do
		sum += v
	return sum

-- uses const CHANCES dict
local function spinTheWheel(sumOfChances)
	local randValue =, sumOfChances)
	local runningCount = 0
	for k,v in pairs(CHANCES) do
		runningCount += v
		if randValue < runningCount then
			return k

-- test
sumOfChances = getSumOfChances()
testDict = {}

for i = 1, 1000 do
	local val = spinTheWheel(sumOfChances)
	if testDict[val] == nil then
		testDict[val] = 1
		testDict[val] += 1

for k,v in pairs(testDict) do

An advantage of this kind of approach is that you don’t necessarily have to change all the values when you add a new item to the chances list. For example, lets say we start with two items that are common and equally likely to be chosen. We could assign ea of them the value 100. In that case, the spinner would choose a rand nbr between 0 and 200 with 0-100 going to the first and 1-200 to the second. If we wanted to add a new item that was twice as likely to be chosen as our baseline items, then it could be given the value 200 and the others would stay as they are. If a fourth item was only 1% as likely to be chosen as one of our two baseline items, then it would be given a value of 1. This makes rare items VERY rare as the number of items in the list increases. To combat that you could spin twice: once for a category (rare vs common vs uncommon), then again for a specific item in the category.
Anyway, just some additional ideas. GL with your game!

1 Like

In addition to the Lua math.random function, Roblox offers a Random class that offers slightly diff functionality.

The complaint about your code being “inaccurate” is probably related to the use of the math.random() function. Since you put 0,100 as the arguments, that function actually includes both of those values as options. The default behavior of math.random() without args is to return a decimal value in range [0,1) – includes 0 but not 1. When you pass arguments like math.random(m,n), the behavior changes so that it returns an integer value in range [m,n]–includes both the m and the n as choices. This means your math.random(0,100) includes an extra value (0,1,2…100 = 101 values). I hope that makes sense. You could likely fix your code into something you’re happy with by changing that line to math.random(0,99). Random:NextInteger(0,100) would be the class equiv and avoids this prob because it returns int values in range [m,n)–excludes the n by design. The :NextNumber method returns decimal numbers in that same [m,n) range.