Yeah, there’s a lot of topics about this, but I can’t seem to wrap my head around the explanation for this. How do you implement it, and, how does it work like that?
Here’s my code for the luck system if you’re wondering, its pretty simple but trustworthy nonetheless.
local weight = {
} orb = {
{'Speed', 1}
},
speed = {
{'CommonSpeed', 1/2},
{'UncommonSpeed', 1/4},
{'RareSpeed', 1/8},
{'EpicSpeed', 1/16},
{'LegendarySpeed', 1/32},
{'MythicalSpeed', 1/64},
{'EtherealSpeed', 1/128},
{'UltimateSpeed', 1/256}
,
boost = {
{'Boost1', 0.75},
{'Boost2', 0.25},
}
}
function ChanceRoll(table: table, luck: number)
local Chance = Random.new():NextNumber()
local Counter = 1
for _, v in ipairs(table) do
Counter -= v[2]
if Chance >= Counter then
return {v[1], Chance}
end
end
if Counter > 0 then
return {table[#table][1], Chance}
end
end
Depends.
Are you wanting to know more about ones where the luck multiplier is a integer (whole number), or one that supports decimals? The ones with integers are a lot simpler (and is the one I actually know about)
With whole integers (at least the way I do it), you can basically just roll n times, then choose the best
(typically rarest) result out of the rolls.
One implementation of this could be something like this:
local weight = {...} -- however you defined it earlier
function ChanceRoll(table: table, luck: number)
local Best = weight[speed][1] -- just a default value in the event they have 0 luck
for i = 1, luck do
local Chance = Random.new():NextNumber()
local Counter = 1
for _, v in table do
Counter -= v[2]
if Chance >= Counter then
if Chance < Best then -- if it's rarer than the previous pick
Best = {v[1], Chance}
end
break
end
end
if Counter > 0 then
if Chance < Best then -- if it's rarer than the previous pick
Best = {table[#table][1], Chance}
end
end
end
return Best
end
This could actually be simplified a bit, because the weightings you have are in decreasing chance, so a higher value of “chance” would always correlate with something equally rare, or more rare. Given that, the code could instead be:
function ChanceRoll(table: table, luck: number)
local Chance = 0
for i = 1, luck do
Chance = math.max(math.random(), Chance)
-- Set the Chance value to the best option out of the rolls
end
local Counter = 1
for _, v in ipairs(table) do
Counter -= v[2]
if Chance >= Counter then
return {v[1], Chance}
end
end
if Counter > 0 then
return {table[#table][1], Chance}
end
end
yeah that ideally works for a mechanic of my game. this is the finalized code by the way, but how would you make decimals though? i mean, there are those tutorials out there, but its hard to adapt it to my code given that i cant understand it.
function ChanceRoll(table: table, luck: number)
local Chance = 0
for i = 1, luck do
Chance = math.max(Random.new():NextNumber(), Chance)
-- Set the Chance value to the best option out of the rolls
end
local Counter = 1
for _, v in ipairs(table) do
Counter -= v[2]
if Chance >= Counter then
return {v[1], Chance}
end
end
if Counter > 0 then
return {table[#table][1], Chance}
end
end
you can get much better performance and also use decimals if you use some kind of mathematical transformation on the luck value
for example, taking math.pow(a, b) makes the value closer to 1 the lower the value b
then you can adjust b with a sigmoid function so it levels off over time as luck increases
local function sigmoid(n)
-- math.exp(x) = e^x
-- put this into desmos for visualisation
return 1- (1/(1 + math.exp(-n)))
end
local rng = math.random()
local adjustedRng = Math.pow(rng, sigmoid(luck))
i dont think its a good idea to use the other one because for high luck values like 1000 your game wont have enough resources to compute that, and even for low luck values your server will be struggling which causes high ping
doing math.pow(luck, number) just makes the luck higher when number is smaller
and then number is found using the sigmoid function to translate between a readable integer luck value that scales linearly and the actual luck value
yes its basically the same thing but much bettter because you dont have to repeat calculations thousands of times
1/chance is a completely unrelated thing
the sigmoid function just changes your luck number so that it fits with the formula i gave
this code is only for generating a random number like math.random() and then you can use whatever you want to generate values with something like 1/chance
just for clarification (which i missed and apologize about):
i’m trying to apply luck multiplier to an rng system, which is the chance roll function
but thanks for your effort though
here is a really simple method i used in my game back then:
function Roll.RollGlider(Luck)
local GliderTbl = deepCopy(Rarities.Gliders);
table.sort(GliderTbl, function(A, B)
return A.Rarity > B.Rarity;
end)
local LuckMulti = Luck or 1;
warn(LuckMulti);
for Index, Tbl in GliderTbl do
if Tbl.Unobtainable then continue end
local RarityWithLuck = math.round(Tbl.Rarity / LuckMulti);
local Rarity = math.max(1, RarityWithLuck);
if Random.new():NextInteger(1, Rarity) == 1 or Index == #GliderTbl then
return Tbl;
end
end
end