You can write your topic however you want, but you need to answer these questions:
- What do you want to achieve? Keep it simple and clear!
I’m making a simple chance system for someone but I’ve run into an issue. I’m trying to make system that each time grabs a random item (using weights) out of a folder and gives the player that as a prize.
- What is the issue? Include screenshots / videos if possible!
When I run the script for the second time with a different value (tierbox2) it prints the first value as well

- What solutions have you tried so far? Did you look for solutions on the Developer Hub?
I googled it and also tried disconnecting the function but it did not seem to work as intended.
Here’s the local script:
-- First thing to do is setup the player gui
local player = game.Players.LocalPlayer
local frame = script.Parent
local RepStorage = game.ReplicatedStorage
local BoxTemplate = game.ReplicatedStorage.Template
local ChanceController = game.ReplicatedStorage.Remotes.ChanceController
local SpinnerGui = player.PlayerGui:WaitForChild("SpinnerGui")
local RewardBox = SpinnerGui.Spinner:WaitForChild("Reward")
local SpinButton = SpinnerGui.ActivateSpinner.Spin
local claimButtonOnRewardBox = RewardBox.Claim
local main = SpinnerGui.Spinner:WaitForChild("Main")
local crates = main.Crates
local Spintime = 6
local amountoftierboxes = 0
local amountofSecondtolasts = 0
local functiondebounce = false
local TotalBoxesDisplayed = 15 -- THIS NUMBER WILL BE IT'S VALUE - 5, (Just to ensure nothing breaks or the gui does not slip past the screen)
-- Also note that the above is MULTIPLIED by the amount of values in the folder so try not to put it higher than 50
-----------------
---- INITIATOR IS NEW, instead of set these while the game is running, to reduce lag we set it during load
local function Initiator()
-- this should reduce lag by loading the things before hand
-- for each tier box to exist create another frame with those things in it
-- duplicate the "crates"
local children = RepStorage.Tiers:GetChildren()
for i, TierBox in ipairs(children) do
amountoftierboxes = amountoftierboxes + 1
print(TierBox.Name .. " is child number " .. i)
-- create a frame for the folder
local CrateClone = crates:Clone()
CrateClone.Name = TierBox.Name
CrateClone.Parent = crates.Parent
-- get the children of the rep storage one and inject them into the folders
local TotalItemCounter = 0
local LastNumber
-- function bacically gets the children of the folder
local function LoadOutCrates()
local children = RepStorage:FindFirstChild("Tiers")[TierBox.Name]:GetChildren()
warn(RepStorage:FindFirstChild("Tiers")[TierBox.Name])
for i, Item in ipairs(children) do
print(Item.Name .. " is child number " .. i)
-- for each child, clone it or whatever
local Clone = BoxTemplate:Clone()
Clone.Name = Item.Name
Clone.About.ItemName.Text = Item.Name
Clone.About.ItemRarity.Text = tostring(Item.Rarity.Value)
Clone.ImageLabel.Image = "rbxassetid://" .. Item.ImageID.Value
print(Clone)
Clone.Parent = main[TierBox.Name]
TotalItemCounter = TotalItemCounter + 1
--warn(TotalItemCounter)
Clone:SetAttribute("ItemNumber",TotalItemCounter)
print(Clone:GetAttribute("ItemNumber"))
print(TotalItemCounter)
end
end
-- load out the crates and put em in the frame for the amount of times below
local counter = 0
repeat
LoadOutCrates()
print("Loaded")
counter = counter + 1
until counter == TotalBoxesDisplayed
local secondtolastboxNumber
local secondtolastboxobject
LastNumber = TotalItemCounter
secondtolastboxNumber = LastNumber - 1
print(LastNumber)
print(LastNumber - 1)
CrateClone:SetAttribute("TotalNumberofCrates",TotalItemCounter)
CrateClone:SetAttribute("SecondtolastboxNumber", secondtolastboxNumber)
-- get the second to last box object
local children = main[TierBox.Name]:GetChildren()
for i, child in ipairs(children) do
print(child.Name .. " is child number " .. i)
local ItemNumber = child:GetAttribute("ItemNumber")
print(ItemNumber)
if tonumber(ItemNumber) == secondtolastboxNumber or tonumber(ItemNumber) == tostring(secondtolastboxNumber) or tonumber(ItemNumber) == tonumber(secondtolastboxNumber) then
secondtolastboxobject = child
print("Hello")
end
end
print(secondtolastboxNumber)
print("BoxObject = ",secondtolastboxobject)
warn(secondtolastboxobject)
warn(secondtolastboxNumber)
-- instead of making an instance we'll have to make a value
-- MAYBE remove this instead, and instead search for a box NAMED "SecondTolastetc."
secondtolastboxobject.Name = "SECONDTOLASTBOXOBJECT_DO_NOT_REMOVE"
warn("DiddlyDone.")
if secondtolastboxobject.Name == "SECONDTOLASTBOXOBJECT_DO_NOT_REMOVE" then
amountofSecondtolasts = amountofSecondtolasts + 1
else
print("uh")
end
--[[local SectolastBobjectval = Instance.new("ObjectValue")
SectolastBobjectval.Parent = CrateClone
SectolastBobjectval.Value = secondtolastboxobject
SectolastBobjectval.Name = "SecondtoLastObjectValue"
--CrateClone:SetAttribute("secondtolastboxobject",secondtolastboxobject)]]
end
end
Initiator()
wait(5)
if amountoftierboxes == amountofSecondtolasts then
warn("ALL IS GOOD")
else
error("Not the same")
end
local function SetupSpinnerGui(TierBoxName)
if functiondebounce == false then
functiondebounce = true
--
warn("TIERBOXNAME:",TierBoxName)
player.PlayerGui.SpinnerGui.Enabled = true
SpinnerGui.ActivateSpinner.Visible = true
main[TierBoxName].Visible = true
print(main[TierBoxName].Visible)
warn("Hellooo")
-- We have to make the specific thing visible idk how to explain
-- gotta find a way to make it invis
-- Load all the items from the boxes into the gui to give the illusuion of opitions
-- make that thing spin somehow (do it by creating 3 maybe and make a tween of position or sum)
-- set max boxes
-- POSSIBLY SEND A SIGNAL TO THE SERVER NOW so you can load the winning prize onto the second to last slot on the spin.
--[[local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteFunction = ReplicatedStorage:WaitForChild("RemoteFunctionTest")
-- Invoke the function
local newPart = remoteFunction:InvokeServer()
print("The server created the requested part:", newPart)]]
-- This is just for reference ^
-- MAYBE we should wrap this all in a function so when th player presses spin it gets activated
local function SpinAndResult()
print("sent")
warn(TierBoxName)
local result = ChanceController:InvokeServer(TierBoxName)
warn(TierBoxName)
print(result)
local resultImgaeID = "rbxassetid://" .. RepStorage.Tiers[TierBoxName][result].ImageID.Value
-- one the result comes back, change thre second to last box with info of the winning prize!
local secondtolastboxobject = main[TierBoxName]:FindFirstChild("SECONDTOLASTBOXOBJECT_DO_NOT_REMOVE")
-- start editing second to last box
-- decided not to change the name, messes up a lot of stuff
--secondtolastboxobject.Name = result
secondtolastboxobject:FindFirstChild("About"):FindFirstChild("ItemName").Text = result
secondtolastboxobject.About.ItemRarity.Text = RepStorage.Tiers[TierBoxName][result].Rarity.Value -- this one may not work
secondtolastboxobject.ImageLabel.Image = resultImgaeID
if secondtolastboxobject.About.ItemRarity.Text == RepStorage.Tiers[TierBoxName][result].Rarity.Value and secondtolastboxobject.ImageLabel.Image == resultImgaeID and secondtolastboxobject:FindFirstChild("About"):FindFirstChild("ItemName").Text == result then
warn("SHOULD HAVE BEEN SET")
print(secondtolastboxobject:FindFirstChild("About"):FindFirstChild("ItemName").Text,secondtolastboxobject.About.ItemRarity.Text, secondtolastboxobject.ImageLabel.Image )
else
error("We have problem")
end
--[[Clone.Name = result.Name
Clone.About.ItemName.Text = result.Name
Clone.About.ItemRarity.Text = tostring(result.Rarity.Value)
Clone.ImageLabel.Image = "rbxassetid://" .. result.ImageID.Value]]
------------------------------------------------------------------------------------------------------------------------------
-- SET THE BOX RESULT BEFORE THE TWEEN TO ENSURE IT LINES UP
RewardBox.ItemImage.Image = resultImgaeID
RewardBox.ItemName.Text = result
-- start the tweening process
local GoalPositionX
local SizeX
SizeX = TotalBoxesDisplayed - 5
GoalPositionX = math.abs(SizeX)*-1
GoalPositionX = GoalPositionX + 1
local START_POSITION = UDim2.new(0, 0, 0.25, 0)
local GOAL_POSITION = UDim2.new(GoalPositionX, 0,0.25, 0) -- IDk why but -5 just messed it up
local guiObject = player.PlayerGui.SpinnerGui.Spinner.Main:FindFirstChild(TierBoxName)
print(guiObject)
-- set the size so there's enough room
guiObject.Size = UDim2.new(SizeX,0,0.5,0)
local function callback(state)
if state == Enum.TweenStatus.Completed then
print("The tween completed uninterrupted")
elseif state == Enum.TweenStatus.Canceled then
print("Another tween cancelled this one")
end
end
guiObject.Position = START_POSITION
local willPlay = guiObject:TweenPosition(
GOAL_POSITION, -- Final position the tween should reach
Enum.EasingDirection.Out, -- Direction of the easing
Enum.EasingStyle.Quart, -- Kind of easing to apply
Spintime, -- Duration of the tween in seconds
true, -- Whether in-progress tweens are interrupted
callback -- Function to be callled when on completion/cancelation
)
if willPlay then
print("The tween will play")
wait(Spintime)
else
print("The tween will not play")
end
--willPlay:Wait()
print("Hi")
-- wait like 2 seconds then fade in the box with the result (Set the box first then do the fase)
local function AnimateReward()
local descendants = RewardBox:GetDescendants()
-- First make them invis
for index, descendant in pairs(descendants) do
print(descendant.Name)
if descendant:IsA("TextButton") or descendant:IsA("TextLabel") then
--make background trans 1
descendant.BackgroundTransparency = 1
elseif descendant:IsA("ImageButton")or descendant:IsA("ImageLabel") then
-- make image trans 1
descendant.ImageTransparency = 1
end
end
print("Set")
RewardBox.Visible = true
local function TweenIT(ThingToTween)
local Info = TweenInfo.new(1)
if ThingToTween:IsA("ImageLabel") or ThingToTween:IsA("ImageButton") then
local Tween = game:GetService("TweenService"):Create(ThingToTween,Info,{ImageTransparency=0})
Tween:Play()
elseif ThingToTween:IsA("TextButton") or ThingToTween:IsA("TextLabel") then
local Tween = game:GetService("TweenService"):Create(ThingToTween,Info,{BackgroundTransparency=0})
Tween:Play()
end
print("Finished")
end
local descendants = RewardBox:GetDescendants()
-- Loop through all of the descendants of the model and
-- print out their name
TweenIT(RewardBox)
for index, descendant in pairs(descendants) do
print(descendant.Name)
if descendant:IsA("TextButton") or descendant:IsA("ImageLabel") or descendant:IsA("TextLabel") or descendant:IsA("ImageButton") then
TweenIT(descendant)
end
end
-- slowly animate the spinny things
local TweenService = game:GetService("TweenService")
local Object = RewardBox.Spin1
local tweenInfo = TweenInfo.new(
8, -- The time the tween takes to complete
Enum.EasingStyle.Linear, -- The tween style.
Enum.EasingDirection.Out, -- EasingDirection
-1, -- How many times you want the tween to repeat. If you make it less than 0 it will repeat forever.
false, -- Reverse?
0 -- Delay
)
local Tween = TweenService:Create(Object, tweenInfo, {Rotation = 360}) -- Creates the tween with the TweenInfo and what properties you want to change
Tween:Play() -- Plays the tween
local TweenService = game:GetService("TweenService")
local Object2 = RewardBox.Spin2
local tweenInfo = TweenInfo.new(
8, -- The time the tween takes to complete
Enum.EasingStyle.Linear, -- The tween style.
Enum.EasingDirection.Out, -- EasingDirection
-1, -- How many times you want the tween to repeat. If you make it less than 0 it will repeat forever.
false, -- Reverse?
0 -- Delay
)
local Tween = TweenService:Create(Object2, tweenInfo, {Rotation = -360}) -- Creates the tween with the TweenInfo and what properties you want to change
Tween:Play() -- Plays the tween
warn("DONE")
end
AnimateReward()
end
-- call the spin event once the "Spin" button is pressed
local function leftClick()
print("SPIN ACTIVATEDD")
SpinnerGui.ActivateSpinner.Visible = false
SpinAndResult()
end
SpinButton.MouseButton1Click:Connect(leftClick)
--WHILE the spin is going send a signal to the server and get back a return of which one they got
-- Once we get the return, load it onto the the main thing showing what they got
--
wait(4)
functiondebounce = false
else
print("Wait")
end
end
frame.Tier1Box.MouseButton1Click:Connect(function()
SetupSpinnerGui(frame.Tier1Box.Name)
end)
frame.Tier2Box.MouseButton1Click:Connect(function()
SetupSpinnerGui(frame.Tier2Box.Name)
end)
frame.Tier3Box.MouseButton1Click:Connect(function()
SetupSpinnerGui(frame.Tier3Box.Name)
end)
-------------------------------------------------
local function leftClick()
print("RewardClaim Pressed")
-- will be in charge of cleaning up, basicaly deletes all of the crates in the spinner display and resets everything to normal
player.PlayerGui.SpinnerGui.Enabled = false
RewardBox.Visible = false
local children = main:GetChildren()
for i, child in ipairs(children) do
if child:IsA("Frame") and child.Name ~= "Line" and child.Name ~= "Crates" then
child.Visible = false
end
end
end
claimButtonOnRewardBox.MouseButton1Click:Connect(leftClick)
Here’s the server script:
-- make a function that will return a value of which item the player rolled and got, and ALSO give them the object
local ChanceController = game.ReplicatedStorage.Remotes.ChanceController
local RepStorage = game.ReplicatedStorage
local function ChanceSpin(player,TierBoxName)
warn("TIERBOXNAME:",TierBoxName)
-- your list of items, I tend to have these in a seperate module
-- mcox edit, we will define the items table, then add in stuff from the teir box
local items = {
--{Name = "Iron Sword"}, example right here
}
print(TierBoxName)
--print(TierBoxName.Name)
local children = RepStorage:FindFirstChild("Tiers")[TierBoxName]:GetChildren()
for i, child in ipairs(children) do
--print(child.Name .. " is child number " .. i)
-- for eachc child, enter a value,
table.insert(items,{Name = child.Name})
end
print(items)
--[[
a loot table, it's wise to keep these seperate from your item list as it allows you to make
multiple loot tables
needs to be linear, greatest to least, and remember it's based on weight not percentages
--]]
-- Now this is the hard part, we need to calculate the weight here
-- prits the name of the entry hopefully
--local val1, val2 = table.unpack(items[1])
--print(val1)
--print(val2)
warn(items[1]["Name"]) -- WINNER WINNER CHICKEN DINNNNNEEEEERRRRRR
--warn(items["Name"])
--warn(items[1])
--warn(items[1].Name)
--warn(items[1][1])
local lootTable = {
--[[{Item = items[2], Weight = 100}, -- each one of these is an entry
{Item = items[3], Weight = 50},
{Item = items[1], Weight = 20}]]
}
for i, v in ipairs(items) do
print(i, v)
-- We need to figure out the values of items[1]'s' Name so we can search it in the tier box and assign it it's weight based on it's value
local Rarity = nil
Rarity = RepStorage.Tiers[TierBoxName]:FindFirstChild(items[i]["Name"]).Rarity.Value
print(Rarity)
-- now that we have the object's rarity, compare it to the tierbox's attribute
local WeightValue = nil
WeightValue = RepStorage.Tiers[TierBoxName]:GetAttribute(tostring(Rarity .. "Chance"))
print(WeightValue)
-- now put it in this mess of a table
table.insert(lootTable,{Item = items[i], Weight = tonumber(WeightValue)})
--warn(items)
-- warn(i)
--warn(items[tonumber(i)])
--warn({Item = items[i]})
--warn({Weight = tonumber(WeightValue)})
--warn({Item = items[i], Weight = tonumber(WeightValue)})
end
-- used in weight random number generation
local function returnSumOfWeight(lootTable)
local sum = 0
for _, entry in ipairs(lootTable) do
sum = sum + entry.Weight
end
return sum
end
-- returns a random item from given lootTable
local function getRandomItem(lootTable)
-- returns a random number based on total weight of given lootTable
local randomNumber = math.random(returnSumOfWeight(lootTable))
for _, entry in ipairs(lootTable) do
if randomNumber <= entry.Weight then
--warn(entry)
print(entry.Item)
return entry.Item
else
randomNumber = randomNumber - entry.Weight
end
end
end
local Result = nil
-- just for testing, mess around with it how you like
for i = 1, 100 do
local item = getRandomItem(lootTable)
print(item)
print(item.Name)
Result = item.Name
end
warn(Result)
return Result
end
ChanceController.OnServerInvoke = ChanceSpin