How do popular games code their rarity system?

Ive been searching for the best way to implement a rarity system, and i ended up making this code. But the problem ive seen is that the pets odds arent actually what its set at first. For example the common cat’s odds would be 0.5/totalweight instead of 0.5/1 so 50%. I know its obvious but im a bit confused since lets say when they roll the pet, what odds will I show for it? Since if i decide to add new pets, the odds will change since totalweight is higher. So Im wondering how big games like pets go and sol’s rng have odds for each pet/object they roll and if they decide to add more of them for an update, the old ones dont change. How do they do it?

The only other way I can think of is having all the odds add up to 1, but even in that case, if I add new pets, some other pets’ odds will have to change to fit in the odds of the new pet for everything to add up to 1.

local pets = {
    {name = "Common Cat", weight = 1/2},
    {name = "Common Dog", weight = 1/2},
    {name = "Common Bunny", weight = 1/2},
    {name = "Uncommon Fox", weight = 1/10},
    {name = "Uncommon Raccoon", weight = 1/10},
    {name = "Uncommon Deer", weight = 1/10},
    {name = "Rare Eagle", weight = 1/20},
    {name = "Rare Owl", weight = 1/20},
    {name = "Rare Tiger", weight = 1/20},
    {name = "Epic Dragon", weight = 1/100},
    {name = "Epic Serpent", weight = 1/100},
    {name = "Epic Minotaur", weight = 1/100}
}

local totalWeight = 0
for _, pet in ipairs(pets) do
    totalWeight = totalWeight + pet.weight
end

local function hatchPet()
    local randomValue = math.random() * totalWeight
    local cumulativeWeight = 0

    for _, pet in ipairs(pets) do
        cumulativeWeight = cumulativeWeight + pet.weight
        if randomValue <= cumulativeWeight then
            return pet.name
        end
    end

    return "Error: No pet selected"
end

for i = 1, 10 do
    print("Attempt " .. i .. ": " .. hatchPet())
end
1 Like

Games with RNG-esque gameplay are not actual odds, but predefined ones like yours (fun fact: if monetized, is technically against EU regulations).

So basically the odds they set in that table is the ones they show on screen even though these are not the real odds?

Pretty much. You will typically see games with odds adding up to more than 100%, e.g. 3+ items with a 1/2 odds.

Alternatively, you can automatically round these odds out:

local pets = {
	{name = "Common Cat", weight = 1/2},
	{name = "Common Dog", weight = 1/2},
	{name = "Common Bunny", weight = 1/2},
	{name = "Uncommon Fox", weight = 1/10},
	{name = "Uncommon Raccoon", weight = 1/10},
	{name = "Uncommon Deer", weight = 1/10},
	{name = "Rare Eagle", weight = 1/20},
	{name = "Rare Owl", weight = 1/20},
	{name = "Rare Tiger", weight = 1/20},
	{name = "Epic Dragon", weight = 1/100},
	{name = "Epic Serpent", weight = 1/100},
	{name = "Epic Minotaur", weight = 1/100}
}

local totalWeight = 0

for _, pet in pets do
	totalWeight += pet.weight
end

for _, pet in pets do
	print(pet.name, `1 in {math.round(1 / (pet.weight / totalWeight))}`)
end

image

1 Like

Yes I feel like thats the best way but, lets say I add 3 more 1/2 pets, then all the other 1/2 pets will be affected and theyll become like 1/8 or something, which I dont think happen in those big rng games. Thats my main concern I wonder how they manage that

Fake odds, replacing pet.weight / totalWeight with just pet.weight:

local pets = {
	{name = "Common Cat", weight = 1/2},
	{name = "Common Dog", weight = 1/2},
	{name = "Common Bunny", weight = 1/2},
	{name = "Uncommon Fox", weight = 1/10},
	{name = "Uncommon Raccoon", weight = 1/10},
	{name = "Uncommon Deer", weight = 1/10},
	{name = "Rare Eagle", weight = 1/20},
	{name = "Rare Owl", weight = 1/20},
	{name = "Rare Tiger", weight = 1/20},
	{name = "Epic Dragon", weight = 1/100},
	{name = "Epic Serpent", weight = 1/100},
	{name = "Epic Minotaur", weight = 1/100}
}

for _, pet in pets do
	print(pet.name, `1 in {math.round(1 / pet.weight)}`)
end

image

2 Likes

See but thats completely insane. Lets say theres one with 1/1000, if I add an other 1/2 then the odds is gonna be way lower than 1/1000 and its gonna keep going down the more pets I add. But at the same time it kinda makes sense if u put the commons, uncommons, rares and epics together, it will feel more like the odds are accurate. Its making my head hurt thinking about how to makes this correct its so hard lmao

If you want to display the true odds, you’d just divide the current pet’s weight by the total weight. This of course comes at the cost of slightly reduced readability.

If you want to display nice numbers, and want these numbers to be accurate, you would have to make all your odds add up to a nice round number.

2 Likes

I think ill end up making a mix of the two, ill try to make my odds add up to around 1 so that the odds are clean to show but not completely accurate, close to the real odds. And this way, I can add how many really rare odds to the list of pets and it will only fluctuate the real odds of the others by a little. Pretty sure this is how sol’s rng does it.

But that way I also cant add other 1/2 pet odds since it will fluctuate too much. The only way to make that possible would be to add additional eggs with these pets in them so that it doesnt fluctuate the other pets’ odds in other eggs and also this way we dont have one single egg with all the pets in them.

2 Likes