• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Lua Reward box using chance for each item

leonardo ramos

Veteran OT User
Joined
Dec 7, 2016
Messages
190
Reaction score
369
I'm reading a little about programming while I have free time at work, so I take my paper and pen and try to write some code to practice and when I get home I write it on the moon and see if it works. today I tried to make a script that used a table to calculate a list of prizes for a reward box. this list contained id, chance, and count {x, y}. Until then, okay. however I do not know how to make it calculate the chance among the items on the list. I researched a little and saw some examples where people use

local r = math.random (1,100)
if r <= chance then
...
end

but there is a possibility that the player may receive more than one item, or none of them. what I would like to do was a script that forced the server to give some of them, but with different odds for each item
 
Say you have 4 items with different probabilties, {A,4}, {B, 5}, {C, 1} and {D, 10}.
The probabilities sum up to 20, so you could do the following:
pseudocode:
Code:
    RNG = random(0, A+B+C+D) -- sums up to 20
    if RNG => 0 &&  < 5 then -- between 0 and 4 (A probability)
        choose A
    else if RNG => 5 && < 9 --between 5 and 9 (A + B probability)
        choose B
    else if RNG => 9 && < 10 --between 9 and 10 (A+B+C probability)
        choose C
    else --last item means you iterated through the rest of the items and the RNG wasnt in their range so theres no need to compare
        choose D

Now obviously, you won't do all manually, you will have to make a loop to itarate through all the items and sum the probabilites while comparing with the RNG to see if its in the range of said item.

At least that would be my aproach, would love to see someone elses
 
Say you have 4 items with different probabilties, {A,4}, {B, 5}, {C, 1} and {D, 10}.
The probabilities sum up to 20, so you could do the following:
pseudocode:
Code:
    RNG = random(0, A+B+C+D) -- sums up to 20
    if RNG => 0 &&  < 5 then -- between 0 and 4 (A probability)
        choose A
    else if RNG => 5 && < 9 --between 5 and 9 (A + B probability)
        choose B
    else if RNG => 9 && < 10 --between 9 and 10 (A+B+C probability)
        choose C
    else --last item means you iterated through the rest of the items and the RNG wasnt in their range so theres no need to compare
        choose D

Now obviously, you won't do all manually, you will have to make a loop to itarate through all the items and sum the probabilites while comparing with the RNG to see if its in the range of said item.

At least that would be my aproach, would love to see someone elses

yes, but how could I automatically do this in a list with more items? if I want to have a large variety it would be stressful to use 1 if and 19 elseif
 
Code:
function getRandomItem()
    items = {
        ["A"] = 4,
        ["B"] = 5,
        ["C"] = 1,
        ["D"] = 10
    }
    total_sum = 0
    for _, v in pairs(items) do
        total_sum = total_sum + v
    end
    RNG = math.random(0, total_sum)
    sum = 0
    item = 0
    for i, v in pairs(items) do
        sum = sum + v
        item = i
        if RNG >= sum - v and RNG < sum then
            break
        end
    end
    return item
end
tested it with:
Code:
prob = {
    ["A"] = 0,
    ["B"] = 0,
    ["C"] = 0,
    ["D"] = 0
}
for i = 0, 100 do
    n = getRandomItem()
    prob[n] = prob[n] + 1
end
for i, v in pairs(prob) do
    print(i .. " was selected " .. v .. " times")
end
the output was:
Code:
C was selected 2 times
D was selected 53 times
A was selected 24 times
B was selected 22 times
 
this would have been better in a support thread, since this isn't related to programming/scripting as a whole, it's related to tfs.
Lua:
local items = {
    {id = 2160, count = {1, 50}, chance = 80},
    {id = 2148, count = {60, 100}, chance = 80}
}

local function generateItemList()
    local finalList = {}
    for _, item in ipairs(itemList) do
        local itemRand = math.random(100) -- random chance for each individual item listed in the list
        if itemRand <= item.chance then
            finalList[#finalList + 1] = item -- insert item into a new index of finalList
        end
    end
    return finalList   
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local itemList = generateItemList()
    local container = player:addItem(2000)
    for _, item in ipairs(itemList) do
        container:addItem(item.id, math.random(item.count[1], item.count[2]))
    end
    item:remove()
    return true
end
 
this would have been better in a support thread, since this isn't related to programming/scripting as a whole, it's related to tfs.
Lua:
local items = {
    {id = 2160, count = {1, 50}, chance = 80},
    {id = 2148, count = {60, 100}, chance = 80}
}

local function generateItemList()
    local finalList = {}
    for _, item in ipairs(itemList) do
        local itemRand = math.random(100) -- random chance for each individual item listed in the list
        if itemRand <= item.chance then
            finalList[#finalList + 1] = item -- insert item into a new index of finalList
        end
    end
    return finalList 
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local itemList = generateItemList()
    local container = player:addItem(2000)
    for _, item in ipairs(itemList) do
        container:addItem(item.id, math.random(item.count[1], item.count[2]))
    end
    item:remove()
    return true
end
If there is nothing in the table from finalList, would this code error when adding the items? (just curious.)
I also don't understand how/when it looks at the table "items", but I might just be missing it. :p


In either case for OP, it sounds like you want to force the player to receive a minimum of 1 item from the list, but the maximum amount of items isn't determined?

I wouldn't complete your task the way Bogart has suggested as it fits 2/3 of the criteria mentioned above.
The way bogart was completing the random chance guarenteed 1 item with random chance but would be very clunky to use if you wanted to have multiple items given out in a reward chest.
(I've used his method before, but forced the chance to be out of 100/1000/10000 so I could calculate the item chance easier.)

I'd do it like above in static's script, because it fits 2 criteria. (random chance for each item, and the maximum amount of items isn't determined.)
However, like Bogart's script it's missing that final 'something' to fit 3/3 criteria.

If the finalList returned no results, I'd simply ask the script to re-run that function again and again until it returned at least 1 result thereby achieving all 3 criteria.

^ however the above does have an increasingly smaller chance that it could run the script forever and never get a result.
You could add a failsafe that increases the chance of each item by 1, each time the script iterates through the list thereby ensuring that it doesn't run forever and still maintain the randomness of the result for as long as possible.
(so the maximum amount of iterations would be (100 - the highest chanced item), thereby forcing the script to eventually reach a gaurenteed item)
(you could also have the function run through X number of times, before skewing the chances to force the script to finish)
(maximum iterations with the above change would be (X # of times + 100 - the highest chanced item))
Although this would skew the amount of items given to players ever so slightly upwards, and for those extremely unlucky situations (script wise), would actually becoming luckier and luckier for the affected player.
^ Note that with a sufficiently large list of items (20+) in the original table this is truely only for a failsafe and the chance of it happening is so miniscule that it's almost laughable to even have the failsafe included after 10 attempts of true randomness.

umm, sorry for the block of text, I'll just stop here.
 
Welp, I derpd a second there, thought he only wanted 1 item lol, static'a way is the correct one if you wanted to give 1 or more items.
 
If there is nothing in the table from finalList, would this code error when adding the items? (just curious.)
I also don't understand how/when it looks at the table "items", but I might just be missing it. :p


In either case for OP, it sounds like you want to force the player to receive a minimum of 1 item from the list, but the maximum amount of items isn't determined?

I wouldn't complete your task the way Bogart has suggested as it fits 2/3 of the criteria mentioned above.
The way bogart was completing the random chance guarenteed 1 item with random chance but would be very clunky to use if you wanted to have multiple items given out in a reward chest.
(I've used his method before, but forced the chance to be out of 100/1000/10000 so I could calculate the item chance easier.)

I'd do it like above in static's script, because it fits 2 criteria. (random chance for each item, and the maximum amount of items isn't determined.)
However, like Bogart's script it's missing that final 'something' to fit 3/3 criteria.

If the finalList returned no results, I'd simply ask the script to re-run that function again and again until it returned at least 1 result thereby achieving all 3 criteria.

^ however the above does have an increasingly smaller chance that it could run the script forever and never get a result.
You could add a failsafe that increases the chance of each item by 1, each time the script iterates through the list thereby ensuring that it doesn't run forever and still maintain the randomness of the result for as long as possible.
(so the maximum amount of iterations would be (100 - the highest chanced item), thereby forcing the script to eventually reach a gaurenteed item)
(you could also have the function run through X number of times, before skewing the chances to force the script to finish)
(maximum iterations with the above change would be (X # of times + 100 - the highest chanced item))
Although this would skew the amount of items given to players ever so slightly upwards, and for those extremely unlucky situations (script wise), would actually becoming luckier and luckier for the affected player.
^ Note that with a sufficiently large list of items (20+) in the original table this is truely only for a failsafe and the chance of it happening is so miniscule that it's almost laughable to even have the failsafe included after 10 attempts of true randomness.

umm, sorry for the block of text, I'll just stop here.
completely forgot
did someone say performance?
Lua:
local items = {
    {id = 2160, count = {1, 50}, chance = 80},
    {id = 2148, count = {60, 100}, chance = 80}
}

local function generateItemList()
    local finalList = {}
    for _, item in ipairs(itemList) do
        local itemRand = math.random(100) -- random chance for each individual item listed in the list
        if itemRand <= item.chance then
            finalList[#finalList + 1] = item -- insert item into a new index of finalList
        end
    end
    return finalList   
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local itemList = generateItemList()
    while #itemList == 0 do
        itemList = generateItemList()
    end
    local container = player:addItem(2000)
    for _, item in ipairs(itemList) do
        container:addItem(item.id, math.random(item.count[1], item.count[2]))
    end
    item:remove()
    return true
end
 
local boxes = {
[5880] = {
items = {{2148, 10,20},{2148, 1, 5}},
rareitems = {{2160, 1,10}},
urareitems = {{2150, 1,2}},
rarechance = 10,
urarechance = 3 } }

local box = boxes[item.itemid]
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
local rd = math.random(1, 50)
if rd <= box.urarechance then
local it = box.urareitems[math.random(#box.urareitems)]
local qt = math.random(it[2],it[3])
player:addItem(it[1], qt)
return true
elseif rd > box.urarechance and rd <= box.rarechance then
local it = box.rareitems[math.random(#box.rareitems)]
local qt = math.random(it[2],it[3])
player:addItem(it[1], qt)
return true
elseif rd > box.rarechance then
local it = box.items[math.random(#box.items)]
local qt = math.random(it[2],it[3])
player:addItem(it[1], qt)
return true
end
return true
end


server returned data/actions/scripts/byleo/boxes.lua:27: 'end' expected <to close 'function' at line 11> near 'item'

but every i insert a new 'end' in the code the server returns '<eof>' expected near 'end'
 
server returned data/actions/scripts/byleo/boxes.lua:27: 'end' expected <to close 'function' at line 11> near 'item'

but every i insert a new 'end' in the code the server returns '<eof>' expected near 'end'
this line is outside of the function.
Lua:
local box = boxes[item.itemid]
your script tabbed, for easier reading. (no edits made.)
Lua:
local boxes = {
  [5880] = {
    items = {{2148, 10,20},{2148, 1, 5}},
    rareitems = {{2160, 1,10}},
    urareitems = {{2150, 1,2}},
    rarechance = 10,
    urarechance = 3
  }
}

local box = boxes[item.itemid]
function onUse(player, item, fromPosition, target, toPosition, isHotkey)
  local rd = math.random(1, 50)
  if rd <= box.urarechance then
    local it = box.urareitems[math.random(#box.urareitems)]
    local qt = math.random(it[2],it[3])
    player:addItem(it[1], qt)
    return true
  elseif rd > box.urarechance and rd <= box.rarechance then
    local it = box.rareitems[math.random(#box.rareitems)]
    local qt = math.random(it[2],it[3])
    player:addItem(it[1], qt)
    return true
  elseif rd > box.rarechance then
    local it = box.items[math.random(#box.items)]
    local qt = math.random(it[2],it[3])
    player:addItem(it[1], qt)
    return true
  end
  return true
end
 
Last edited:
y1NHs6W.png
 
Back
Top