Help on a random chance feature [Egg hatching system]

So if you use the number 1 as the 1/1M chance then up to now if the random number lands on 1 then you get that pet otherwise you get something else.

If you then ask if the number is less than or equal to 10 for the next rarity then its asking if its equal to:

1,2,3,4,5,6,7,8,9,10

Which is 10 numbers however since the number 1 is used for the 1/1M chance, its actually only checking then following numbers:

2,3,4,5,6,7,8,9,10

Which is only 9 numbers. 1M / 9 = 111111.111111 which is roughly a 1/111111 chance instead of a 1/100k.

I haven’t seen any examples of how they do it exactly but I would presume they would just use a similar system to this. If I find anything about it though I’ll let you know.

NOTE: you could use a more complex system by creating some kind of dictionary of rarities like you have but then picking random numbers out of the 1000000 chances and adding them to that rarity which would link that specific number to each egg type.

This may be overly complex though for no good reason. Ill run some tests and see if it makes much of a difference given that there are no true random numbers.

ah so that’s why the pets would seem harder than it should be, thanks

Yes please do let me know if you find anything on that because for bgs they have some extremely high chances like millions and billions and it all seems really accurate so i wanted to know how they did it

also, the original way i did it was that the random number would be 1,100 and each of the chances would have to be equal to 100 (just a weighted selection) would it be more accurate to do that? also if so how would i do it with decimal chances (the example 0.001 pet)

Either way should be roughly equal but up to you which one you implement.

If you want to work with decimals you could just pick a random number between 1 and max and then divide it by something e.g. 1 / 1000 = 0.001

I see,

So on the quote before where you talked about how it should be 11 instead of 10 how would i do that with a higher number like how should i replace 100,000 with its accurate chance (random number is 1,1M)

Also, i’ve heard of something called random.new so would it be easier to make a chances system with that?

So this is not the only way to do this but you could try something like this.

local rarities = {
    ["Secret3"] = {["Chance"] = 1, ["Rarity"] = "Secret"};
    ["Secret2"] = {["Chance"] = 3, ["Rarity"] = "Secret"};
    ["Secret1"] = {["Chance"] = 10, ["Rarity"] = "Secret"};
    ["Legendary3"] = {["Chance"] = 100, ["Rarity"] = "Legendary"};
    ["Legendary2"] = {["Chance"] = 500, ["Rarity"] = "Legendary"};
    ["Legendary1"] = {["Chance"] = 2500, ["Rarity"] = "Legendary"};
    ["Epic1"] = {["Chance"] = 50000, ["Rarity"] = "Epic"};
    ["Rare1"] = {["Chance"] = 300000, ["Rarity"] = "Rare"};
    ["Uncommon1"] = {["Chance"] = 1646886, ["Rarity"] = "Uncommon"};
    ["Common1"] = {["Chance"] = 3000000, ["Rarity"] = "Common"};
}

You can then use a function to get the total chance based from all rarities in the dictionary.

function GetRarityTotalChance()
	local total = 0
	for k, v in next, rarities do
		total += v["Chance"]
	end
	return total
end

local TotalChance = GetRarityTotalChance()

Now to get the correct Min and Max values for each number e.g. 1/1M was 1 and 1/100K was 2 - 11 we need to run a function to calculate this. The following function does that.

function SetRandomChanceMinMax()
	local currentMin = 0
	local currentMax = 0
	for k, v in next, rarities do
		currentMin = currentMax + 1
		currentMax = currentMax + v["Chance"]
		rarities[k]["Min"] = currentMin
		rarities[k]["Max"] = currentMax
		--print(k .. "    " .. rarities[k]["Min"] .. "     " .. currentMin .. "     " .. rarities[k]["Max"] .. "     " .. currentMax)
	end
end

SetRandomChanceMinMax()

All that’s left is to pick a random pet, this function picks a random value and checks if it is between the Min and Max of each pet rarity. Once it finds the correct one it will return the values from each dictionary.

function choosePet()
	
	local randomChance = math.random(1, TotalChance) --Chance for specific pet
	
	for k, v in next, rarities do
		if randomChance >= v["Min"] and randomChance <= v["Max"] then
			local rarity = v["Rarity"]
			--local rarityTab = petModule.pets[k]
			--local chosenPet = rarityTab[1]
			return k, rarity --Replace K with chosen pet
		end
	end
end

NOTE: these will need adding or editing to suit your module. Also the choosePet Function will need k removing from the return and changing out for your chosenPet value. Since I didn’t have this value I just returned K for testing purposes

Either should work fine for your purpose. If you’re interested in more detail however this discussion about it may be useful.

math.random() is a global random object and you may make use of it in many different places. This may lead to what appears to be inaccurate Random Chances as the next pseudo random has already been called.

Random.new() creates a new random object with a given seed e.g. tick() and can be used to return pseudorandom integers with :NextInteger(min, max) or number (decimal) (double) using :NextNumber(min,max).
Using Random.new() ensures that you will get the right distribution of rarities as no other script can call it unless you allow it.

2 Likes

I see,
A few questions i have is i don’t know what for k, v in next is
and if i were to put all the egg modules into one module would i just have to do something like petModule.CommonEgg = {

}

i also see that it says that random.new is better for fairness so wouldn’t it be better for my case

So for k, v in next, rarities is a loop through the rarities dictionary.

rarities = {
    ["Common"] = 0;
    ["Uncommon"] = 1;
}

for k, v in next, rarities do
    --k is the key so in this loop it would pass over Common and Uncommon
    --v is the value so for common it would be 0 and for uncommon it would be 1
end

NOTE: Do keep in mind that dictionaries have no specific order so it will not always do common first. Just be aware of this when expanding on code and loops involving these

you could do it like that or you could do something like this:

petModule.Eggs = {
    ["CommonEgg"] = {
        --Common Eggs Here
    }
}

Just whatever you find the easiest to maintain.

Yeah so if you plan to use math.random() in other places then random.new would be better however if you don’t then it wont make much of a difference.

NOTE: Probably worth going with with random.new from the start as it will make the game easier to expand later on.

okay, thank you for all your help and i will test this out once i get the chance and reach out if i have any following questions

No problem :slightly_smiling_face:

Good Luck with your project.

i know this isn’t related but,
how would i go about making a viewport frame into like an image

for example. i have a viewport frame that shows a pet and stuff but i want to store all of that into a image into a module script so i can just access any pets image from anywhere

I’m not totally sure, I haven’t really used Viewport Frames but this discussion might help you.

would this work?

petModule.Eggs = {
        [“Common Egg”] = { 
                Cost = {“Coins”,500},
                Secrets = {“Giant Kitty”,”TV”},
                Rarities = {
                        [“Doggy”] = {[“Chance”] = 000, [”Rarity”] = “Common”}, [“Kitty”] = {[“Chance”] = 000, [”Rarity”] = “Uncommon”}
                }
        }
}

i’d keep going

Thanks [Angiris_treecreeper] (Profile - Angiris_treecreeper - Developer Forum | Roblox)Programmer! This really helped me with a script!

1 Like

Yeah :slightly_smiling_face:, I don’t see why it shouldn’t. As long as you can access all of the data in the way you thought you could then any layout should be fine.

petModule.Eggs = {
	["Common Egg"] = { 
		Cost = {
			"Coins",500 --Was this intended to be ["Coins"] = 500 ?
		},
		Secrets = {
			"Giant Kitty",
			"TV"
		},
		Rarities = {
			["Doggy"] = {
				["Chance"] = 000,
				["Rarity"] = "Common"
			}, 
			["Kitty"] = {
				["Chance"] = 000,
				["Rarity"] = "Uncommon"
			}
		}
	}
}

One note about the cost section of the common egg. Was it intended to be:

cost = {
    ["Coins"] = 500
}

Just wondering as you would currently have to access the cost part like an array e.g.
petModule.Eggs["Common Egg"]["Cost"][1]
instead of:
petModule.Eggs["Common Egg"]["Cost"]["Coins"]

Keep up the good work :+1:

1 Like

for the cost coins i intended it to be cost = {“Coins”,500} so i know what currency it is and how much of it even though there is 1 currency in my game but i added it just for future games and if i will have eggs that cost multiple currencys

also, when i make the pet model should i put values inside the pet like stat multipliers and it’s state (flying or standing for the animation)

Cool, always good to think ahead.

Yeah, you could either put the values in the pet or you could store a current pet in a server script in a
dictionary containing each player and store information about that pet there instead. Either way is fine so whichever you prefer.

hey,
so ive made the script so far and i tested it and the chances seem to have some problems like:
min/maxs are wrong example, for bunny it says the min is 1 (which should be for the tv)

local eggModule = {}

local random = Random.new()

eggModule.Eggs = {
	["Common Egg"] = {
		Cost = {"Coins",500},
		Secrets = {"Giant Kitty","TV"},
		Rarities = {
			["Doggy"] = {["Chance"] = 3750000, ["Rarity"] = "Common",["Percent"] = "37.5"},["Kitty"] = {["Chance"] = 2750000, ["Rarity"] = "Uncommon",["Percent"] = "27.5"},
			["Bunny"] = {["Chance"] = 2500000, ["Rarity"] = "Rare",["Percent"] = "25"},["Bear"] = {["Chance"] = 988794, ["Rarity"] = "Epic",["Percent"] = "9.88"},
			["Deer"] = {["Chance"] = 10000, ["Rarity"] = "Legendary",["Percent"] = "0.1"},["Dragon"] = {["Chance"] = 1000, ["Rarity"] = "Legendary",["Percent"] = "0.01"},
			["Golem"] = {["Chance"] = 200 , ["Rarity"] = "Legendary",["Percent"] = "0.002"},["Giant Kitty"] = {["Chance"] = 5, ["Rarity"] = "Secret",["Percent"] = "5E-05"},
			["TV"] = {["Chance"] = 1, ["Rarity"] = "Secret",["Percent"] = "1E-05"}
		},
		Pets = {
			--Not done with all pets
			["Doggy"] = {game.ReplicatedStorage.Assets.Pets.}
		}
	}
}

function GetRarityTotalChance(eggToHatch)
	local total = 0
	for k, v in next, eggModule.Eggs[eggToHatch].Rarities do
		total += v["Chance"]
	end
	return total
end

function SetRandomMinMax(eggToHatch)
	local currentMin = 0
	local currentMax = 0
	for k, v in next, eggModule.Eggs[eggToHatch].Rarities do
		currentMin = currentMax + 1
		currentMax = currentMax + v["Chance"]
		eggModule.Eggs[eggToHatch].Rarities[k]["Min"] = currentMin
		eggModule.Eggs[eggToHatch].Rarities[k]["Max"] = currentMax
	end
end

eggModule.ChoosePet = function(eggToHatch)
	SetRandomMinMax(eggToHatch)
	local randomChance = random:NextInteger(1,GetRarityTotalChance(eggToHatch))
	
	for k, v in next, eggModule.Eggs[eggToHatch.Rarities] do
		if randomChance >= v["Min"] and randomChance <= v["Max"] then
			local rarity = v["Rarity"]
			local percent = v["Percent"]
			
			local rarityTab = eggModule.Eggs[eggToHatch].Pets[k]
			local chosenPet = rarityTab[1]
			
			return chosenPet, rarity, percent
		end
	end
end

return eggModule

also, how do i do x2 luck
(i know i have to multiply and divide chances but im not sure which ones should get multiplied or divided)

also wondering if you have a discord so i dont have to flood this post lol

Right, It may seem that they’re wrong but its most likely that its because when looping a dictionary it doesn’t do it in a specific order so bunny may be the first see below:

local testDict = {
    ["One"] = 1,
    ["Two"] = 2,
    ["Three"] = 3,
    ["Four"] = 4,
    ["Five"] = 5
}

This dictionary appears to be in order from One to Five however when you print it:

local stringToPrint = ""
	
for k, v in next, testDict do --K is the key e.g. One - Two
    stringToPrint = stringToPrint .. k .. " "
end	

print(stringToPrint)

PrintedDictionary

This may look odd at first however if you make sure to only get and set information based on k, v the key and value of the dictionary loop then it will all work. Just as you said you may get the chances for bunny first as >= 1 and <= 2,500,000 and TV may have its chances as >= 2,500,001 and <= 2,500,001.

So there are probably multiple ways to do this however the easiest may be to pass a luck value into a function for a player and then calculate the chances of the egg based on that luck value. This is similar to what we discussed before however instead of calculating just once, you would calculate each time someone unlocked an egg.

This does depend on if you plan the x2 luck to just affect rare items in the egg or all items in the egg though.

Yeah no problem :slightly_smiling_face:, ill private message it to you.

so my code on the random number chance is fine

also wouldnt for i, v in pairs be better since it goes from start to end