Tables aren't working properly

  1. What do you want to achieve? Keep it simple and clear!
    I have a game where a random player dies every 20 seconds or so and after they die they get removed from the contestants table and when a game starts they get put into that contestants table
  2. What is the issue?
    i have a thing where it checks if theres only 1 contestant it ends the game but it ended it when theres 2 contestants left
  3. What solutions have you tried so far?
    I honestly have no idea of solutions to it

here is my code
RoundsModule:

local module = {}
local randomy = require(script.Parent.Game)
local status = game.ReplicatedStorage.Status

function module.i(length)
	for i=length,0,-1 do
		status.Value = i.." seconds left for a new round to start!"
		wait(1)
	end
end

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

function kill(contestants)
	local random = randomy.Choose()
	for i, v in pairs(game.Players:GetChildren()) do
		if table.find(contestants, v.Name) then
			table.remove(contestants,i)
		end
	end
	workspace[random.Name].Humanoid.Health = 0
	status.Value = random.Name.." died "..#contestants.." people left."
end

function module.sg(length)
	local contestants = {}

	for i, v in pairs(game.Players:GetPlayers()) do
		--[[local tag = Instance.new("StringValue")
		tag.Name = "user"
		tag.Parent = v]]
		table.insert(contestants, v.Name)
		for i, e in pairs(workspace:GetChildren()) do
			if e.Name == v.Name then
				e.HumanoidRootPart.CFrame = workspace.spawn.CFrame
			end
		end
		
	end
	
	for i=length,0,-1 do
		if #contestants == 1
		then
			game.Players[contestants[1]].leaderstats.Wins.Value = game.Players[contestants[1]].leaderstats.Wins.Value + 1
			game.Players[contestants[1]].leaderstats.Coins.Value = game.Players[contestants[1]].leaderstats.Coins.Value + 25
			status.Value = "Everyone died. "..contestants[1].." wins!"
			wait(4)
			game.Players[contestants[1]]:LoadCharacter()
			break
		end
		
		if #contestants == 0
		then
			status.Value = "Everyone left. no-one wins."
			break
		end
		if i == length - 1 then
			status.Value = "A round of russian rouletee has begun."
			wait(2)
		end
		
		if i == length - 10 then
			kill(contestants)
		end

		if i == length - 20 then
			kill(contestants)
		end
		
		if i == length - 30 then
			kill(contestants)
		end
		
		if i == length - 40 then
			kill(contestants)
		end
		
		if i == length - 50 then
			kill(contestants)
		end

		if i == length - 60 then
			kill(contestants)
		end

		if i == length - 70 then
			kill(contestants)
		end
		
		if i == length - 80 then
			kill(contestants)
		end
		
		if i == length - 90 then
			kill(contestants)
		end
		
		if i == length - 100 then
			kill(contestants)
		end
		
		status.Value = toMS(i)
		wait(1)
	end
end

return module

Game module


local module = {}

function module.Choose()
	local randomPlayer
	
	local randomPlayer = game.Players:GetPlayers()[math.random(1,#game.Players:GetPlayers())]
	
	
	return randomPlayer
end

return module

Main script:

local r = require(script.Rounds)
local g = require(script.Game)
local plrcount = 0

game.Players.PlayerAdded:Connect(function()
	plrcount = plrcount + 1
end)

game.Players.PlayerRemoving:Connect(function()
	plrcount = plrcount - 1
end)

repeat 
	wait(1)
	game.ReplicatedStorage.Status.Value = "1 more player and the game will start ("..plrcount.."/2)"
until plrcount >= 2

while wait() do
	if plrcount < 2 then
		repeat
			wait(1)
			game.ReplicatedStorage.Status.Value = "1 more player and the game will start ("..plrcount.."/2)"
		until plrcount >= 2
	end
		
	r.i(10)
	r.sg(120)
end

and i know that players can die even if they arent in the contestants table

How many players have you tried testing it with? Just a curiosity question to see what extent it’s been pushed.

1 Like

Also what is the max amount of players you can have in your game at one time.

1 Like

3 players. and the max is 10 (30 characters)

Give me a couple minutes to boot up studio. I think I have a couple ideas.

1 Like

I think some contestants don’t get in a table somehow

Alright, time for an extremely long reply with code that hasn’t even been tested. Let’s get it. First, I did change quite a number of things. I’m going to start with the main ServerScript.

local rounds = require(script.Rounds)
--local g = require(script.Game)
local plrcount = 0

----

game.Players.PlayerAdded:Connect(function()
	plrcount = plrcount + 1
end)

game.Players.PlayerRemoving:Connect(function(plr)
	plrcount = plrcount - 1
	rounds.removeContestant(plr.Name)
end)

----

--[[
repeat 
	wait(1)
	game.ReplicatedStorage.Status.Value = "1 more player and the game will start ("..plrcount.."/2)"
until plrcount >= 2
--]]

while wait() do
	
	if plrcount < 2 then
		repeat 
			wait(1)
			game.ReplicatedStorage.Status.Value = "1 more player and the game will start ("..plrcount.."/2)"
		until plrcount >= 2
	end
		
	rounds.i(10)
	rounds.sg(120)
end

First, I did change a few variable names just for me to read the code better. This is definitely a good tip to take into consideration. The better variables names you have the more readable your code is.

Back to the code, the first change I made was just to comment out local g = require(script.Game). Unless you use it in your script at another place, I don’t see it being required there. I also actually didn’t use the game module at all because I took that function and put it into the rounds script. If that was all the game module was used for then it was more or less pointless.
I also commented out the repeat loop before the while wait() do because it’s repetitive as you use the same code in the while loop.

Rounds Module Script:

local roundsModule = {}

local contestants = {}
local status = game.ReplicatedStorage.Status

function roundsModule.i(length)
	for i=length,0,-1 do
		status.Value = i.." seconds left for a new round to start!"
		wait(1)
	end
end

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

-----

local function ChoosePlayer()
	local randomNum = math.random(1, #contestants)
	local randomPlayer = contestants[randomNum]
	return randomPlayer
end

local function kill()
	local found = false
	while found == false do
		local remove = ChoosePlayer()
		for i, plr in pairs(game.Players:GetChildren()) do
			if plr.Name == remove then
				local place = table.find(contestants, remove)
				table.remove(contestants, place)
				
				game:GetService("Workspace"):FindFirstChild(remove).Humanoid.Health = 0
				status.Value = remove.." died ".. #contestants.. " people left."
				
				found = true
			end
		end	
		wait()
	end
	
end

function roundsModule.removeContestant(user)
	if table.find(contestants, user) then
		table.remove(contestants, table.find(contestants, user))
	end
end

function roundsModule.sg(length)

	--- Add Players to Contestants
	for i, plr in pairs(game.Players:GetChildren()) do
		--[[local tag = Instance.new("StringValue")
		tag.Name = "user"
		tag.Parent = v]]
		table.insert(contestants, plr.Name)
		for i, user in pairs(workspace:GetChildren()) do
			if user.Name == plr.Name then
				user.HumanoidRootPart.CFrame = workspace.spawn.CFrame
			end
		end
		
	end
	
	-- Game Loop (?)
	local firstSecond = false
	for i=length, 0, -1 do
		
		if #contestants == 1 then
			game.Players[contestants[1]].leaderstats.Wins.Value = game.Players[contestants[1]].leaderstats.Wins.Value + 1
			game.Players[contestants[1]].leaderstats.Coins.Value = game.Players[contestants[1]].leaderstats.Coins.Value + 25
			status.Value = "Everyone died. "..contestants[1].." wins!"
			wait(4)
			game.Players[contestants[1]]:LoadCharacter()
			contestants = {}
			break
		
		elseif #contestants == 0 then
			status.Value = "Everyone left. no-one wins."
			contestants = {}
			break
		end
		
		if i == length then
			status.Value = "A round of russian rouletee has begun."
			wait(2)
		end
		
		if length % i == 0 and firstSecond == true then
			kill()
		end
		
		status.Value = toMS(i)
		wait(1)
		firstSecond = true
		
	end
end

return roundsModule

Alright this script had quite a number of changes.

  1. Everything that I didn’t change I just moved to the top of the script. Everything changed is at the buttom under the -----. One thing I did change though is I moved the contestants table to the top and out of the .sg function in order to allow all functions access to it.
  2. I changed your randomy function, this is what I moved from the Game Module, and I changed it to
    local function ChoosePlayer(). Before you were getting any player that was in the game, but you actually want to only choose a player that is a contestant. randomNum is obvious, it picks a random index based on the number of players that are contestants and returns the randomPlayer at that index in the table.
  3. The Kill() function was the biggest change I made. Firstly, your old code was using the function that picked any player and not just contestants. Why is this bad? If you have max 10 players and every 10 seconds you’re killing off a player, you don’t give enough time if a player that is not a contestant is picked.
    What I did was made a while loop that would run until it found a player that was in the game and was equal to remove, which is the random player gotten from ChoosePlayer(). This is a better choice to do because if it doesn’t find a player that is in the server and was chosen then it should pick another. Following that, I just remove the user from contestants and run your code. I also set found to true which ends the while loop, you could also use break.
  4. I added a function [removeContestant] that removes a user from the contestant table if they leave the server completely. This function is called back in the Main Script in the .PlayerRemoving event and passes the plr.Name to remove. Not a big change but a needed to clear the unneeded players during the round.
  5. Finally the .sq function. The only change to the first loop was just variables for readability and I changed :GetPlayers() to :GetChildren(). I honestly didn’t know :GetPlayers() was a thing.
    During the actual game loop, I first changed the two if #contestants == statements into one if/elseif and before the break for each I reset the contestants table to empty contestants = {}.
    I also changed i == length - 1 to just i == length, but unless you already tried that and it didn’t work, this would change your status right at the beginning rather than after 1 seconds, but overall not a problem.
    Finally, I just removed the 10 if-statements you had and created one modulo statement. if you didn’t know, module (%) is the same as division but returns the remainder. For example: 3 % 2 = 1 because 3 / 2 has a remainder of 1. I used this because you kill-off people every 10 seconds, so doing 100 (length) - i % 10 == 0 means it would only run and kill someone every 10 seconds as long as it’s after the first second (achieved by adding a bool variable and setting to true after wait(1)).

I don’t know if this will fix the contestant issue and ending with more than 1 player left, but I hope the change in code (even if something is wrong) will help point in the right direction. If it doesn’t work still or get an error then let me know. (Whoops, very long message but lots of explaining)

2 Likes

I’d suggest inserting a value, like a BoolValue, inside of the player if they are inside the table, like

if player:FindFirstChild("RandomValue") then
table.insert(yourTable,playerName)
end
2 Likes

I’m gonna try it && thanks for the helpon the other stuff :smiley:

(edit:that’s was possibly one of the longest posts I have ever seen lol)

That’s probably a great idea. but I check if the contestants are only 1,I can use variables && stuff but It would take quite a while

That would be a good idea if a feature was added like an afk thing where you only want to add the players that aren’t afk.

2 Likes

I’m aware but it’s mostly just the explaining. You could post the code but I feel like that defeats the purpose. You’re on here to get help and me just posting code and telling you good luck won’t teacher you anything or help at all.

1 Like

I think humanoid.Running could work :thinking:

(edit:I dont remember the name lol.)

Possibly but that was meant more as a button that you click example.

1 Like

Would be quite easy the button will just put an instance inside the player on click and when a game starts it checks if they don’t have the instance inside them and when they click again it removes the instance.

Exactly but did the problem fix or haven’t tested yet.

1 Like

Haven’t tested since im on phone right now lol.

Tested it out. seems to work fine but takes like a min to kill someone // start the function.

Which function (30 charactersssss)

1 Like
		if length % i == 0 and firstSecond == true then
			kill()
		end