Right now I am attempting to make a system that gives cash (or in my game, "Explode Points") to the player with the best KO to wipeout ratio at the end of every round. The problem is, I have absolutely no idea how to do that. So far I made a weird little script that makes values in a folder that I'm going to try and take the highest value from:
local function findWinner() local children = game.Players:GetChildren() for _, child in pairs(children) do local stats = child:WaitForChild("leaderstats") if stats then --making values local KOs = stats.KOs local Deaths = stats.Wipeouts local newValue = (KOs.Value / Deaths.Value) local PnewValue = Instance.new("IntValue", game.ReplicatedStorage.WinnerValues) PnewValue.Name = child.Name PnewValue.Value = newValue wait(10) KOs.Value = 0 Deaths.Value = 0 PnewValue:Destroy() end end local winnerFolder = game.ReplicatedStorage.WinnerValues end
I hope I didn't break the rules by not providing any code for finding the value, but the other questions on this site just didn't make any sense to me or work at all. So how do you go about doing this? (In case you need it, the function is fired every 120 seconds)
Edit: Be sure to tell me if there's a more efficient way to track all of the stats than putting them in a folder, because I'm sure there is but I honestly have no idea
Edit2ElectricBoogaloo: After hours of trying, I still haven't gotten it to work so far. Both answers give me a similar error where the winner is returned as a nil value, and there isn't a system for ties.
Here's my new script where I mostly used the second answer but used some aspects from the one I originally thought answered my question:
local function FindWinner() local children = game.Players:GetPlayers() local highestnumber = -10000 local winner = nil local playerCountChildren = game.Players:GetPlayers(); local playerCount = #playerCountChildren; for _, child in pairs(children) do if child:FindFirstChild('leaderstats') then local stats = child.leaderstats local KOs = stats.KOs local Deaths = stats.Wipeouts local newValue = (KOs.Value / Deaths.Value) if Deaths.Value == 0 and KOs.Value ~= 0 then newValue = KOs.Value end if newValue > highestnumber then highestnumber = newValue winner = child end if playerCount == 1 then winner = child highestnumber = newValue end end end return winner, highestnumber end
Here is the loop I made at the bottom, in case I'm utilizing it wrong:
while true do for a=120,1,-1 do print(a) wait(1) end print ('0') setupMap() local winner, highestnumber = FindWinner() print (winner.Name.. " is the winner with a KDR ratio of " ..highestnumber) local message = Instance.new('Message',game.Workspace) message.Text = (winner.Name.. " is the winner with a Kill Death Ratio of " ..highestnumber .."!") local winPlayer = game.Players:FindFirstChild(winner.Name) if winPlayer then local winStats = winPlayer:FindFirstChild("leaderstats") if winStats then local winCash = winStats:FindFirstChild("ExplodePoints") winCash.Value = winCash.Value + 500 wait(5) end end resetValues() message:Destroy() wait() end
local players = game:GetService('Players') local function make_table() -- resets the table for when we find a new high kdr local winners = {} winners.player_objects = {} winners.strings = {} setmetatable(winners,{ -- calls when we try and set something new in winners -- used to insert strings in to winners.strings -- and move player objects to player_objects __newindex = function(tabl, key, value) table.insert(winners.strings, key) tabl.player_objects[key] = value; end; }) return winners end local function FindWinner() local highestnumber = -1 local winners = make_table() for _, child in pairs(game.Players:GetPlayers()) do local stats = child:FindFirstChild('leaderstats') if stats then local KOs = stats.KOs local Deaths = stats.Wipeouts local kdr = (KOs.Value / Deaths.Value) -- Dividing by 0 = inf, so make it your kos value. if Deaths.Value == 0 then kdr = KOs.Value end if kdr > highestnumber then highestnumber = kdr -- reset table winners = make_table() -- calls __newindex in the metatable, so we can automatically -- do a couple of things winners[child.Name] = child; elseif kdr == highestnumber then -- don't reset table; add player. winners[child.Name] = child; end KOs.Value = 0; Deaths.Value = 0; end end -- Shortens the number to four incase it's a UUGE(heh) decimal. return winners, tostring(highestnumber):sub(1,4) end local function start() while wait(.5) do local winner_objects, kdr = FindWinner() local strings = winner_objects.strings -- \n makes a new line local winner_text winner_text = (#strings == 0 -- if #strings == 0 then and 'No one won \n' -- elseif #strings == 1 then or #strings == 1 and ('%s won with a kdr of %s'):format(strings[1], kdr) -- else or ("There was a tie between %s"):format(table.concat(strings, ", ").. ' with a kdr of '..kdr )) print(winner_text) if #strings > 0 then for i,v in pairs(winner_objects.player_objects) do local winStats = v:FindFirstChild("leaderstats") local winCash = winStats and winStats:FindFirstChild("ExplodePoints") if winCash then winCash.Value = winCash.Value + 500 wait(5) -- going to cause the script to hang end end end end end local stats = { ['KOs'] = 10; ['Wipeouts'] = 0; ['ExplodePoints'] = 0; } players.PlayerAdded:connect(function(player) local ls = Instance.new("NumberValue") ls.Name = 'leaderstats'; for i,v in pairs(stats) do local val = Instance.new("NumberValue", ls) val.Name = i; val.Value = v; end ls.Parent = player end) start()
local Winners_Cache = {} -->> Store info as a table in your script, no need for external values local function FindWinner() local Highest = {} for _,Player in pairs (game.Players:GetPlayers()) do local Stats = Player:FindFirstChild("leaderstats") -->> Having an if statement is pointless if it is WaitForChild if Stats then local KOs,WOs = Stats:WaitForChild("KOs"),Stats:WaitForChild("WOs") -->> Name your statistics consistently, 'KOs' and 'Wipeouts' doesn't really work local KDR = KOs.Value/WOs.Value if WOs.Value == 0 then -->> To stop it from being infinite KDR = KOs.Value elseif KOs.Value == 0 and WOs.Value > 0 then KDR = -WOs.Value end if not Highest[1] or Highest[1].KDR < KDR then -->> If highest hasn't been assigned to yet, or if this KDR is bigger Highest = {{Player = Player,KDR = KDR}} -->> Set it -->> Highest is now a holder for a number of players, not just one, to allow for ties end delay(10,function() -->> Waits 10 seconds without slowing down the code KOs.Value,WOs.Value = 0,0 end) end end table.insert(Winners_Cache,Highest) return Highest end local Winners = FindWinners() for _,Winner in pairs (Winners) do -->> Loop through every winner print(Winner.Player.Name.. " is the winner with a KDR of " ..Winner.KDR.."!") -->> After this, just change the Explode Points value inside Winner.Player's leaderstats end
EDIT:
My bat about the errors. It errored on line 18 because the first time the code runs, Winners.KDR
did not exist so it was trying to compare nil
with KDR
.
I've also edited it to work for tying.
Some more tips:
Use ServerStorage
instead of ReplicatedStorage
when you want to store things that can't be accessed or changed by players. This reduces the potential for the winners to be hacked if you were using an object system.
Use game.Players:GetPlayers()
to get players, not :GetChildren()
.
Hope I helped!
~TDP
--[[Edits: You can use "local winner = findWinner()" to know who's the winner, so you can basically do this: winner.leaderstats.Points.Value = winner.leaderstats.Points.Value+10 There was also a bug so that it does this: find winner, waits 10 seconds, delete the data, and it restarts it doesnt like do all of it at the same time, like it will perform one by one so I basically made it so the WinnerValues clear all children, and made another function that clears the player's score. ]] function resetScores() local children = game.Players:GetChildren() local highestnumber = -10000 local winner = nil for _, child in pairs(children) do if child:FindFirstChild('leaderstats') then local stats = child.leaderstats local KOs = stats.KOs local Deaths = stats.Wipeouts KOs.Value = 0 Deaths.Value = 0 end end end function findWinner() local children = game.Players:GetChildren() local highestnumber = -10000 local winner = nil for _, child in pairs(children) do if child:FindFirstChild('leaderstats') then local stats = child.leaderstats local KOs = stats.KOs local Deaths = stats.Wipeouts local newValue = (KOs.Value / Deaths.Value) if Deaths.Value == 0 and KOs.Value ~= 0 then --prevent it from saying "inf" for the ratio newValue = KOs.Value end local PnewValue = Instance.new("IntValue", game.ReplicatedStorage.WinnerValues) PnewValue.Name = child.Name PnewValue.Value = newValue if newValue > highestnumber then highestnumber = PnewValue winner = child end -- KOs.Value = 0 --Deaths.Value = 0 -- PnewValue:Destroy() end end local winnerFolder = game.ReplicatedStorage.WinnerValues return winner end local winner = findWinner() local message = Instance.new('Message',workspace) message.Text = 'The winner is '..winner.Name wait(10) game.ReplicatedStorage.WinnerValues:ClearAllChildren() resetScores() message:remove()