RNG Helper Resource (small)

RNG Helper

In reminiscence of this recently posted video:

I heavily disagree with it (even though it’s probably ragebait). So, I am publishing a custom resource (by me) that implements a simple customizable RNG system, just to prove how easy it is. This is a premade resource, something I used for a game/project that already exists.

I don’t want to make it seem like I’m attacking this Youtuber; I’m just sharing a personal opinion, and I want to share this with the community.


Overview

Returns a RNG objects, from a dictionary of weights.

RNGModule.new(weights: { [string]: number }): {}

Returns a single string value based on a randomization algorithm calculated by the provided weights.

RNGModule:Generate(): string

Modifies a single rarity value internally (useful for luck based multipliers)

RNGModule:UpdateRarity(item: string, value: number)

Updates all rarities based on current internal weights

NOTE: There is no need to call this after modifying a weight using :UpdateRarity(), it is done internally.

RNGModule:UpdateRarities()

Example

Here’s an example of it’s use:

local module = require(workspace.RNGModule)

local rarities = {
    Apple = 1, 
    Banana = 9 
}

local myGenerator = module.new(rarities)

for i = 1, 10 do 
    print(myGenerator:Generate()) 
end

Bananas on average will be generated 9x times more frequently than apples.
And here are the results!

image

Conclusion

Thank you for using my system. As a heads up, I will be taking any recommendations for optimizations or nitpicks on this code, and it will be changing constantly.


The Resource

RNGModulev2.rbxm (1.5 KB)

13 Likes

And since the code is so short, I’ve provided here

--!strict

local rngModule = {}

rngModule.__index = rngModule

function rngModule.new(weights: { [string]: number })
	local self = setmetatable({}, rngModule)
	
	if weights == nil then
		error("Weights cannot be empty!")
	end
	
	self.Rarities = nil
	self.Weights = weights
	
	self:UpdateRarities()
	
	return self
end

function rngModule:Generate()
	if self.Rarities == nil then
		error("Initialize rarities before generating!")
	end
	
	local selector = 0
	local chosen = math.random()

	for item, rarity in self.Rarities do
		selector += rarity

		if selector >= chosen then
			return item
		end
	end
end

function rngModule:UpdateRarity(item, value)
	self.Weights[item] = value
	
	self:UpdateRarities()
end

function rngModule:UpdateRarities()
	local totalWeight = 0
	local newRarities = {}
	
	for item, weight in self.Weights do
		if type(weight) ~= "number" or weight < 0 then
			error("Invalid weight entry " .. tostring(weight) .. " for " .. item)
		end

		totalWeight += weight
	end
	
	for item, weight in self.Weights do
		local newWeight = weight / totalWeight
		
		newRarities[item] = newWeight
	end
	
	self.Rarities = newRarities
end

return rngModule
1 Like

I like it, nice and simple, def will use it in the future.
Since it’s so short you might as well also add in some error handling and documentation.

local rngModule2 = {}

rngModule2.__index = rngModule2

function rngModule2.new(rarities: {})
	-- Check if the rarity table is empty
	if next(rarities) == nil then
		error("Rarities cannot be empty!")
	end
	
	-- Calculate total rarity
	local totalRarity = 0
	for _, rarity in rarities do
		if type(rarity) ~= "number" or rarity < 0 then
			error("Invalid rarity entry " .. rarity)
		end
		totalRarity += rarity
	end
	
	local self = setmetatable({}, rngModule2)
	
	-- Temporarily holds the normalized rarities for the current object
	local newRarities = {}
	
	-- Normalize rarities
	for name, rarity in rarities do
		newRarities[name] = rarity / totalRarity
	end
	
	self.Rarities = newRarities
	
	return self
end

function rngModule2:Generate()
	local selector = 0
	local chosen = math.random()
	
	-- Iterate through rarities
	for item, rarity in self.Rarities do
		selector += rarity -- Increment selector by rarity...
		
		--...and if the selector exceeds or equals the random number return the current item
		if selector >= chosen then
			return item
		end
	end
end

return rngModule2
2 Likes

Would be great if you could implement a luck system.

2 Likes

Yup! That’s what this system is, I guess you could call it a luck system. It generates unique ids based of off a chance value.

He meant that you could implement a luck modifier so that you could pass a luck variable and get rarer items easier.

1 Like

Ah, my apologies. I didn’t add a “luck system”, but I updated to where you can now change rarity values with ease, along with some more error handling.

I will also add some documentation.

Yep, exactly what I meant, for example if let’s say “LuckMutliplier” is 2 then the more rare items will be 2 times more common. I have heard that you can somehow implement this with raising some value X (I think 0.25?) to the power of rarity.

Interesting. I would probably do it by adding a percentage of the most common value to everything then recalculating the weights. As all the values increase, the ratio between them and the higher numbers become closer to 1, making them more common.

1 Like

Haven’t used this yet but I plan on it in the future as math.random isn’t so reliable by itself