Hello, I’ve seen a lot of people trying to make loot tables and I decided to come up with a flexible and easy to use module, just so developers can approach the situation stress free.
Summary
This module can optionally use probabilities between 0 and 1 (total percentages of all items must always add up to 100%)
This module can optionally use Weights (any number that you want including decimals, essentially allowing you to use odds/fractions/ratios by giving each item a ‘weight’)
This module can help convert odds to probabilities and vice versa.
This module can handle any event that depends on probabilities/odds. (but most people will probably use it for loot crates and similar constructs)
Below is a quick concept using a jelly bean jar as an example, we’ll use probabilities and odds (but either one is optional and can be converted into one another if needed.)
You will need a decent understanding of Dictionary Tables.
Rules
When creating your jelly bean jar, it MUST contain a nested table with a key named “Weight” OR “Chance”, after that you can add any other keys that you need.
Example using odds
--red bean odds are 1/11 (11,000 total, but only 1,000 possible) - (0.09% probability)
local jar = {
RedBean = {
Weight = 1000, --must contain this value called "Weight"
Whatever = "Blah" --your own values that you may need
},
BlueBean = {
Weight = 10000,
Whatever = "Blah"
}
}
Example using probability
--red beans probability of being chosen is 25% (or 1/4 odds)
local jar = {
RedBean = {
Chance = 0.25 --must contain this value called "Chance"
Whatever = "Blah" --your own values that you may need.
},
BlueBean = {
Chance = 0.75
Whatever = "Blah"
}
}
local LootMananger = require(game.ServerScriptService.LootManager)
Step THREE
Create your jar
Create your jar of jelly beans using Weights
--use any number you want
local jar = {
RedBean = {Name = "MrRedBean", Weight = 50}, --50 red beans
GreenBean = {Name = "MrGreenBean", Weight = 1000}, --1000 green beans
BlueBeen = {Name = "MrBlueBean", Weight = 0.5} -- 0.5 blue beans
}
Create your jar of jelly beans using Percentages
--all chances must add up to 100% in order to calculate correctly.
local jar = {
RedBean = {Name = "MrRedBean", Chance = 0.25}, --25% of the jar is red beans
GreenBean = {Name = "MrGreenBean", Chance = 0.7} -- 70% of the jar is green beans
BlueBeen = {Name = "MrBlueBean", Chance = 0.05} -- 5% of the jar is blue beans
}
Step FOUR
Get a random jelly bean out of the jar.
local selectedBean = LootManager:GetRandomSlot(jar)
print(selectedBean.Name .. ":" .. (selectedBean.Weight or selectedBean.Chance))
Step FIVE
Compare the name to a list of rewards/items (and other things)
local beanReward = beans[selectedBean.Name]:Clone()
beanReward.Parent = player.Backpack --lol bean tool
That’s all folks, if you have any questions please post them here.
Quick question about your random selection system.
You appear to be adding a lot of values to a central table, then randomly selecting a value from that table, which while working fine at 100 values, if we want a highly detailed system with potentially 10,000 total values that can create a huge performance spike.
Im just interested in why you chose this over a weight based system?
If OP isn’t sure how to create a good weight based system, here is one I wrote…
RarityManager.RegularCaseRarityValues = {
{Rarity = 1, Chance = 60};
{Rarity = 2, Chance = 25};
{Rarity = 3, Chance = 14};
{Rarity = 4, Chance = 0.9};
{Rarity = 5, Chance = 0.1};
}
RarityManager.PremiumCaseRarityValues = {
{Rarity = 3, Chance = 50};
{Rarity = 4, Chance = 45};
{Rarity = 5, Chance = 5};
}
function RarityManager.GetCaseRarityValue(premium)
local targetTable = premium and RarityManager.PremiumCaseRarityValues or RarityManager.RegularCaseRarityValues
local selectedNumber = math.random(0, 100)/10
local counted = 0
for _, chanceData in pairs(targetTable)do
counted = counted + chanceData.Chance
if counted >= selectedNumber then
return chanceData.Rarity
end
end
end
This is just pulled out of a random project of mine. The random logic for selectedNumber which returns a random number from 0-100 to a decimal point of 1 could be improved, but otherwise this is a clean and efficient way of handling a weighted probability issue.
It works like so… If an item has a 30% chance of being one, the code will “allocate” the first 30 numbers of 1-100, RNG comes up anywhere from 0-29, you win the 30% item. The next item, which is say 20%, will be allocated the numbers 30-50, and if the RNG throws up a number between 30-50, you win the 20% item
Added a GetChances() function to convert Weights into percentages. (for visualization purposes and more)
Update 7/26/2020
I renamed LootTable to LootManager
i’ve completely reconstructed this module, and will continue to add utilities and other useful functions, like easy to use fortune wheels and case systems (please provide suggestions)
I’ve added support for both weights and percentages directly. (weights can also use decimals now too, but don’t confuse the weight in decimal form with percentages)
Weight/Chance tables are now fully flexible and can contain custom data to help you
compare the randomly chosen element to a list of rewards. (or even comparing to angles on a fortune wheel).
there we go @RuizuKun_Dev, i’ve provided a pastebin link and i don’t think i’ll need github contributors just yet, the module is kinda small now compared to my old module.
Would anyone know of a good tutorial or resource that would help me script a fortune wheel like shown in the OP’s media example?
I know how to make a wheel spin with a decal on it, but not how to make it stop at the reward point.
What I have at the moment:
A wheel and click detector. Once clicked, the wheel spins and stops at a random location.
What I can do:
Once clicked, an event fires to the server. The server chooses the reward (e.g. local selectedBean = LootManager:GetRandomSlot(jar)) the player will get and sends that info back to the client.
What I still need to learn:
The client will then spin the wheel so it lands on the “reward image” associated with the reward received.
now the server will just randomly choose one of these slots, after the server has chose a slot then it will just make the client do a spin animation that gradually slows down. Now once the wheel reaches a certain speed just make the wheel stop when it reaches the desired angle provided by the slots table.
NOTES
1). this is a ‘fixed’ spin and the reward is already chosen by the server before the wheel even starts spinning on the client.
2). Its way easier to compare angles to a ImageLabel (in a SurfaceGui or ScreenGui) then it is to compare angles to a parts orientation (atleast it was for me)
3). If you want to play fast sounds locally for the wheel spin then you need this (or some sort of custom method)
4). if you don’t want a ‘fixed’ spin then you could also try to emulate some physics of a spinning wheel but I couldn’t really imagine how that is done, and it would have to be handled by the server (so people can’t exploit the spin) which wouldn’t be smooth.