Help with a table in script

hi, please help me real quick with this:

  1. What do you want to achieve? i already have the script working (server script), but what i want to make is to make is each player to already have his percentage at the beginning of each game, and the killer to be chosen only at a certain point in the game and therefore in the script

  2. What is the issue? i don’t know how to do this, in this script it choses the percentages and the killer in the same moment, while i want it to choose the percentages at the beginning, and after other stuff happens, like map voting and other, it finally chooses the killer at that point

  3. What solutions have you tried so far? i tried fixing it myself but i couldn’t find the soultion :frowning:

this is the script, mess with it however you want

local chances = {}

local function chooseKiller(plrs)

	for plr, points in pairs(chances) do
		if table.find(plrs, plr) == nil then
			table.remove(chances, table.find(chances, plr))
		end
	end

	for _, plr in pairs(plrs) do
		if table.find(chances, plr.Name) == nil then
			chances[plr.Name] = 1
		end
	end
	local names = {}
	for plr, points in pairs(chances) do
		if points >= 1 then
			for i = 1, chances[plr], 1 do
				table.insert(names, plr)
			end
		end
	end

	local chosenName = names[math.random(1, table.getn(names))]
	local chosenKiller = game:GetService("Players"):FindFirstChild(chosenName)

	for plr, points in pairs(chances) do
		chances[plr] += 1
	end

	chances[chosenName] = 0

	return chosenKiller
end

print(chooseKiller(game:GetService("Players"):GetPlayers()))

thanks in advance ;D

Why don’t you change the percentages after the killer has been chosen, that way they’ll be preset for next round.

i’ll try it, how would i do that?

Let’s clean that up a bit.

First of all, you’re choosing a killer solely based on their existence on the table, and not by their chances of getting chosen. Ex: “1, 2, 3, 4”, math.random will take any of these. In this case, you want to ensure that the function has more chances of taking someone with a higher “chance” variable.

-- example code
local players = {
    ["Player1"] = 12,
    ["Player2"] = 10,
    ["Player3"] = 8,
    ["Player4"] = 6
    -- And for how many you would like.
}
-- Here, we want to choose a killer. To choose the one with a higher "chance",
-- we'll use what's called a roulette wheel selection.

A roulette wheel selection still chooses players at random, except the ones with the highest “chance” will have more chances at being picked.

Applying that technique, we can do:

Code
-- First, declare the Players service. This will save you a lot of work.
local Players = game:GetService("Players")

-- Then, if you'd like, the tables.
local players = {}
--[[
    We just need this table to store the players in the game, as well as their chances.
    Each player will have a chance to be the killer, depending on how long they've been in the game,
    and if they have been the killer before.
]]

-- Now let's get into the functions.
-- First, we want to create a function to assign the players to the table.
function assignPlayersChance(players)
    for index, player in pairs(players) do
        table.insert(players, player.Name)
        players[index] = 1 -- initialize the chances of the players
    end
    chooseMap() -- run the following function
end

function chooseMap()
    --[[
        This is up to you. You can write this at your will, so I won't write it for you.
        Because I don't know how you want to do it, or how it works.
        By the name of the function, you should be able to figure it out.
    --]]

    round()
end

function assignKiller(players)
    --[[
        Here, we want to choose the killer.
        Once chosen, we'll assign their chance to 0.
        This is so they can't be the killer again.
        Then, we'll increase the chances of the other players.
    ]]
    local function rouletteSelection(player, chances)
        --[[
            Now, this function will take two arguments: player and chances.
            This should be obvious, but I'll explain it anyway.
            Within this function, we want to choose a random player from the table.
            However: we want to choose a player that has a higher chance of being the killer based on their chances.
            For that, we'll use the Roulette Wheel Selection algorithm.
        ]]
        local total: number = 0
        for key, chance in pairs(players) do
            total += chance -- add the chances of the players to the total
        end

        local random = math.random() -- get a random number between 0 and 1
        local runningTotal: number = 0
        local selectedKiller: string -- initialize the selectedKiller variable as a string.
        -- this string is local, and will be returned at the end of the function.
        for player, chance in pairs(players) do
            local probability = chance / total -- get the probability of the player
            runningTotal = runningTotal + probability -- add the probability to the runningTotal

            if runningTotal > random then -- check if the runningTotal is greater than the random number
                selectedKiller = player -- if it is, set the selectedKiller to the player
                players[player] = 0 -- set the killer's chance to 0
                break -- break the loop
            end
        end
        return selectedKiller
    end

    local killer: string = rouletteSelection() -- initialize the killer variable as a string
    for key, chance in pairs(players) do
        players[key] += 1 -- increase the chances of the players, change this to your liking.
        if table.find(players, killer) then -- check if the killer is in the table
            players[key] = 0 -- if they are, set their chance to 0
        end
    end
    return killer -- return the string, so "killer = assignKiller(players)" will work.
end

-- lastly, run your function that handles the round.
function round()
    local killer = assignKiller(players)
    -- code
    chooseMap() -- run the chooseMap function, looping it will make it a round.
end

-- Let's create two events. One for when a player joins, and one for when a player leaves.

Players.PlayerAdded:Connect(function(player)
    table.insert(players, player.Name) -- insert the player into the table
    players[player.Name] = 0 -- initialize the chances of the player
end)

Players.PlayerRemoving:Connect(function(player)
    for index, player in pairs(players) do -- iterate through the table
        if table.find(players, player.Name) then -- check if the player is in the table
            table.remove(players, table.find(players, player.Name)) -- if they are, remove them from the table
        end
    end
end)

Note: this code (is not, or may not be) perfect. if anyone sees mistakes, please fix them, thanks.

thank you so much, if my script already repeats like a round system, do i have to remove the last part of the script?

made a few mistakes, please check again.

also, what do you mean by “last part”?

i mean, in the script, at a certain point, you repeat the map choose function, saying “run the chooseMap function, looping it will make it a round.”, but if my script already repeats with a round system, do i have to remove the part with “function round()” and the part where map choose function repeats? i don’t know if i’ve been clear

Edit: also, where have you made the mistakes?

It looks like he edited his comment so the mistakes could be gone by now.
Also you should look at the function round() part and merge it with your existing code.

ok, thanks. do i have to remove the second chooseMap function, too? what is it for? thanks once again :slight_smile:

The code I provided is merely an example of how your script should work.

  • The first function initializes all players’ “chance” variable.
  • The chooseMap function is, as you mentioned, “I want everything else to happen before choosing the killer”. After the map is chosen, it moves on choosing said killer.
  • Then, the next function denotes the killer. That’s the main point of what you’re looking for.
  • Lastly, round is mainly the game itself. How you would manage the round and stuff.
  • After that, I ran chooseMap again, so it runs from chooseMap after the round ends, essentially looping the game, as: assignPlayers > chooseMap > assignKiller > round > chooseMap > assignKiller > round.

Also, I fixed that once again. I noticed that Copilot did a few mistakes (yes, I use Copilot).

1 Like

THANK YOU SO MUCH, it finally works if I create a script based on your code. but if I also want to apply it to a module script (which I didn’t create, it’s from Alvinblox), it doesn’t work. I’m trying to apply your code to both scripts because I want to use some Alvinblox script functions and basically build on that. its “killer” is the “piggy”, so i converted the part where your code says “killer” to “piggy”, but it doesn’t work. here is the whole module script, can you help me find the error and fix it? Thanks in advance :))

local module = {}

local status = game.ReplicatedStorage.Status


--THIS IS A PART OF YOUR CODE!!!


-- First, declare the Players service. This will save you a lot of work.
local Players = game:GetService("Players")

-- Then, if you'd like, the tables.
local players = {}
--[[
    We just need this table to store the players in the game, as well as their chances.
    Each player will have a chance to be the Piggy, depending on how long they've been in the game,
    and if they have been the Piggy before.
]]

-- Now let's get into the functions.
-- First, we want to create a function to assign the players to the table.
function assignPlayersChance(players)
	for index, player in pairs(players) do
		table.insert(players, player.Name)
		players[index] = 1 -- initialize the chances of the players
	end
end


--END OF YOUR CODE!!!


function module.Intermission(length)
	for i = length,0,-1 do
		status.Value = "Intermission - "..i..""
		wait(1)
	end
end

function module.SelectChapter() --chosing map

	-- i will code here
	
end

function module.ChoosePiggy(players)
	
	--THIS IS A PART OF YOUR CODE!!!
	
	
    --[[
        Here, we want to choose the Piggy.
        Once chosen, we'll assign their chance to 0.
        This is so they can't be the Piggy again.
        Then, we'll increase the chances of the other players.
    ]]
	local function rouletteSelection(player, chances)
        --[[
            We'll use a task.spawn to run this function as we call it.
            Now, this function will take two arguments: player and chances.
            This should be obvious, but I'll explain it anyway.
            Within this function, we want to choose a random player from the table.
            However: we want to choose a player that has a higher chance of being the Piggy based on their chances.
            For that, we'll use the Roulette Wheel Selection algorithm.
        ]]
		local total: number = 0
		for key, chance in pairs(players) do
			total += chance -- add the chances of the players to the total
		end

		local random = math.random() -- get a random number between 0 and 1
		local runningTotal: number = 0
		local chosenPiggy: string -- initialize the chosenPiggy variable as a string.
		-- this string is local, and will be returned at the end of the function.
		for player, chance in pairs(players) do
			local probability = chance / total -- get the probability of the player
			runningTotal = runningTotal + probability -- add the probability to the runningTotal

			if runningTotal > random then -- check if the runningTotal is greater than the random number
				chosenPiggy = player -- if it is, set the chosenPiggy to the player
				players[player] = 0 -- set the Piggy's chance to 0
				break -- break the loop
			end
		end

		return chosenPiggy
	end


	local Piggy: string = rouletteSelection() -- initialize the Piggy variable as a string
	for key, chance in pairs(players) do
		players[key] += 1 -- increase the chances of the players, change this to your liking.
		if table.find(players, Piggy) then -- check if the Piggy is in the table
			players[key] = 0 -- if they are, set their chance to 0
		end
	end
	return Piggy -- return the string, so "Piggy = assignPiggy(players)" will work.
end

--END OF YOUR CODE!!!



function module.DressPiggy(piggy)
	--this is to convert the killer in their selected skin, don't worry about it
end

function module.TeleportPiggy(player)
	--i will code here
end

function module.TeleportPlayers(players, mapSpawns)
	--another part not to worry about
end

function module.InsertTag(contestants,tagName) --this is to find the players
	for i, player in pairs(contestants) do
		local Tag = Instance.new("StringValue")
		Tag.Name = tagName
		Tag.Parent = player
	end
end

local function toMS(s)
	return ("%02i:%02i"):format(s/60%60, s%60)
end

function module.StartRound(length,piggy,chapterMap)
	local outcome

	game.ServerStorage.GameValues.GameInProgress.Value = true


	for i = length,0,-1 do

		if i == (length - 20) then
			--the killer will spawn at this point, but i know how to do that
		end

		local contestants = {}

		local isPiggyHere = false

		local Escapees = 0

		for i, player in pairs(game.Players:GetPlayers()) do

			if player:FindFirstChild("Contestant") then
				table.insert(contestants,player)
			elseif player:FindFirstChild("Piggy") then
				isPiggyHere = true
			end

			if player:FindFirstChild("Escaped") then
				Escapees = Escapees + 1
			end

		end

		status.Value = toMS(i)

		if Escapees > 0 then
			outcome = "escaped"
			break
		end

		if not isPiggyHere then
			outcome = "piggy-left"
			break
		end

		if #contestants == 0 then
			outcome = "piggy-killed-everyone"
			break
		end

		if i == 0 then
			outcome = "time-up"
			break
		end

		wait(1)
	end

	if outcome == "piggy-killed-everyone" then
		--i will code here

	elseif outcome == "time-up" then
		--same thing here

	elseif outcome == "piggy-left" then
		--same
		
	elseif outcome == "escaped" then
		--and once again

	end

	wait(5)
end

function module.RemoveTags()

	--this is where the round starts again, i know what to do ;)
	
end


--THIS IS A PART OF YOUR CODE!!!


Players.PlayerAdded:Connect(function(player)
	table.insert(players, player.Name) -- insert the player into the table
	players[player.Name] = 0 -- initialize the chances of the player
end)

Players.PlayerRemoving:Connect(function(player)
	for index, player in pairs(players) do -- iterate through the table
		if table.find(players, player.Name) then -- check if the player is in the table
			table.remove(players, table.find(players, player.Name)) -- if they are, remove them from the table
		end
	end
end)

--END OF YOUR CODE!!!


return module

Edit: also, is there any way to make a gui that shows each player their percentage to be the killer/piggy?

use a RemoteEvent to send their percentage to the client and display it using a TextLabel

-- Server
local players = {}
local RemoteEvent: RemoteEvent -- insert remote

for _, player in pairs(Players:GetPlayers()) do
    if players[player.Name] then
        RemoteEvent:FireClient(player, chance)
     end
end

-- Client
local RemoteEvent: RemoteEvent -- same thing
local displayChance: TextLabel -- wherever your textlabel is.
RemoteEvent.OnServerEvent:Connect(function(chance)
    displayChance.Text = tostring(chance)
    -- or whatever you want to do with the chance.
end)

ok, thank you. what about the script i sent, have you found the error?

hi, have you found the error in my script?

Yes. You’re using a module from AlvinBlox.
Otherwise, I’ve fixed the code for you. Try to see if it works.

local module = {}

-- Services
local status = game.ReplicatedStorage.Status
local Players = game:GetService("Players")

-- tables
local players = {}

-- assign the players to the table
function assignPlayersChance(players)
	for index, player in pairs(players) do
		table.insert(players, player.Name)
		players[index] = 1 -- initialize the chances of the players
	end
end

function module.Intermission(length)
	for i = length,0,-1 do
		status.Value = "Intermission - "..i..""
		task.wait(1) -- please use task.wait() instead of wait() as it's more efficient.
	end
end

function module.SelectChapter() -- choose the map (chapter?)
	-- i will code here
end

function rouletteSelection(players)
    local total: number = 0
    for key, chance in pairs(players) do
        total += chance
    end
    local random = math.random()
    local runningTotal: number = 0
    local chosenPiggy: string
    for player, chance in pairs(players) do
        local probability = chance / total
        runningTotal = runningTotal + probability

        if runningTotal > random then
            chosenPiggy = player
            break
        end
    end
    return chosenPiggy
end

function module.ChoosePiggy(players)
	local Piggy: string = rouletteSelection(players)
	for player, chance in pairs(players) do
        players[player] += 1
        if player == Piggy then
          players[player] = 0
        end
      end
	return Piggy
end

function module.DressPiggy(piggy)

end

function module.TeleportPiggy(player)

end

function module.TeleportPlayers(players, mapSpawns)

end

function module.InsertTag(contestants, tagName) --this is to find the players
	for i, player in pairs(contestants) do
		local Tag = Instance.new("StringValue")
		Tag.Name = tagName
		Tag.Parent = player
	end
end

local function toMS(s)
	return ("%02i:%02i"):format(s/60%60, s%60)
end

function module.StartRound(length,piggy,chapterMap)
	local outcome: string
	game.ServerStorage.GameValues.GameInProgress.Value = true
        for i = length,0,-1 do
            if i == (length - 20) then
                --the killer will spawn at this point, but i know how to do that
            end
            local contestants = {}
            local isPiggyHere = false
            local Escapees = 0
            for i, player in pairs(game.Players:GetPlayers()) do
                if player:FindFirstChild("Contestant") then
                    table.insert(contestants,player)
                elseif player:FindFirstChild("Piggy") then
                    isPiggyHere = true
                end
                if player:FindFirstChild("Escaped") then
                    Escapees += 1
                end
            end

            status.Value = toMS(i)

            if Escapees > 0 then
                outcome = "escaped"
                break
            end

            if not isPiggyHere then
                outcome = "piggy-left"
                break
            end

            if #contestants == 0 then
                outcome = "piggy-killed-everyone"
                break
            end

            if i == 0 then
                outcome = "time-up"
                break
            end

            task.wait(1)
        end

	if outcome == "piggy-killed-everyone" then
		--i will code here

	elseif outcome == "time-up" then
		--same thing here

	elseif outcome == "piggy-left" then
		--same
		
	elseif outcome == "escaped" then
		--and once again

	end

	task.wait(5)
end

function module.RemoveTags()
	
end


Players.PlayerAdded:Connect(function(player)
	table.insert(players, player.Name)
	players[player.Name] = 0
end)

Players.PlayerRemoving:Connect(function(player)
	for index, player in pairs(players) do
		if table.find(players, player.Name) then
			table.remove(players, table.find(players, player.Name))
		end
	end
end)

return module

Next time please avoid Alvinblox. Simply because he’s more of a spoonfeeder than an actual mentor. If you really want to learn coding, it’s better to practise by writing, experimenting and try again. Personally, I’ve watched Alvinblox, but he was not helpful at all.

See, the problem with most Luau “mentors” is that (not just Luau. however, there’s no good crash course for Luau created by someone, “reliable”: any other language, such as Python or Rust, has some good crash courses for you to begin with) they tell you to do this do that, and you won’t learn.

You’re supposed to understand how code works, not how to write it. If you don’t know how to understand code, writing it is pointless. Code is not just pure magic that you can paste in, you have to know how to use it correctly, that’s why you can’t learn from watching simple tutorials, less from Alvinblox.

it works until the roulette part, i tried to find the error but i couldn’t find it. have you?

thanks for the advice, you are right, alvinblox gives too much without explaining, but as you can see i cleared all the codes inside the functions, to code it myself. I just needed a structure to build upon, nothing more. I don’t want someone else to code my game, I just need a hint and a basis to have an outline. thank you again :slight_smile:

Can I have a view of your code from the roulette part?

it’s the one you gave me

--here was chosen the map

function rouletteSelection(players)
	local total: number = 0
	for key, chance in pairs(players) do
		total += chance
	end
	local random = math.random()
	local runningTotal: number = 0
	local chosenPiggy: string
	for player, chance in pairs(players) do
		local probability = chance / total
		runningTotal = runningTotal + probability

		if runningTotal > random then
			chosenPiggy = player
			break
		end
	end
	return chosenPiggy
end


function module.ChoosePiggy(players)
	
	local Piggy: string = rouletteSelection(players)
	for player, chance in pairs(players) do
		players[player] += 1
		if player == Piggy then
			players[player] = 0
		end
	end

	return Piggy

end

--here there is the part where the killer becomes his skin and the round starts