Luck buffing RNG solution

I had trouble finding a system that let me buff player’s odds in RNG, so I spent a few hours making this solution:

local function GetRandomFromWeightedTable(Table,PropertyName, Rng, Luck)
	PropertyName = PropertyName or "Weight"
	Luck = math.max(Luck or 0, 0)
	Rng = Rng or Random.new()

	local Items = {}
	local Total = 0
	local ItemAmount = 0
	local FalloffStrength = 0.33 -- Inverse Base for the distance log
	local BiggestItem = 0

	for Index,Item in pairs(Table) do
		if Item[PropertyName] and type(Item[PropertyName]) == "number" then
			Items[Index] = Item[PropertyName] 
			Total += Item[PropertyName]
			ItemAmount += 1
			if Item[PropertyName] > BiggestItem then
				BiggestItem = Item[PropertyName]
			end
		end
	end

	if Total <= 0 then
		return nil
	elseif ItemAmount == 1 then
		for i,v in pairs(Table) do
			return v
		end
	end

	-- Luck Adjustment

	local InverseLuck = 1 / Luck
	local LogBase = 1 / FalloffStrength

	for Index,Value in pairs(Items) do
		Value = Value / BiggestItem
		local Distance = math.log(Value / InverseLuck, LogBase)

		if Distance >= 0 then
			Value = Value / ((LogBase) + 2) ^ (Distance)
		else

		end

		Items[Index] = Value
	end

	Total = 0

	for Index,Value in pairs(Items) do
		Total += Value
	end

	for Index,Value in pairs(Items) do
		Value = Value / Total

		Items[Index] = Value
	end 

	local Roll = Rng:NextNumber()
	
	local LastIndex = nil -- Prevent edge case nil returns
	
	for Index,Value in pairs(Items) do
		Roll -= Value
		if Roll <= 0 then
			return Table[Index],Value,Items
		end
		LastIndex = Index
	end
	
	return Table[LastIndex],Items[LastIndex],Items
end

return GetRandomFromWeightedTable

Normally, weighted random selection works by giving each item a weight, where higher weights make an item more common and lower weights make it rarer. The problem is that simply multiplying rare item weights by a luck value often breaks the balance, common items become too weak, rare items become too common, or extremely high luck values make the results feel unrealistic.

This function takes a different approach.

Instead of directly multiplying weights, it gradually compresses the gap between common and rare items using a logarithmic falloff. As luck increases, common items slowly lose some of their dominance while rarer items become progressively more likely to appear. Because the adjustment follows a curve rather than a straight multiplier, the effect stays smooth and predictable, even at high luck values.

Some other details:

  • A luck value of 1 behaves identically to the original weighted table.
  • Higher luck values increasingly favor rarer entries without completely eliminating common ones.
  • After all adjustments are made, the weights are normalized back into probabilities before performing the random roll.

The function returns:

  • The selected item.
  • Its final normalized probability after luck has been applied.
  • The full adjusted probability table (useful for debugging or displaying odds).

Feel free to modify this as I just wanted to help other people with finding one. It works up to 1e100 luck.

6 Likes

I find this pretty helpful :+1:

2 Likes