Query regarding tabling and teleporting

Hi,
Ive got a section of code here:

local assassins = (#eligiblePlayers + (#eligiblePlayers % 2)) / 2
for i = 1, assassins do
		local randIndex = math.random(#eligiblePlayers)
		local randPlayer = eligiblePlayers[randIndex]
		randPlayer.Team = teams["Assassains"]
		--remotes.DisableFootSteps:FireClient(randPlayer)
		table.remove(eligiblePlayers, randIndex)
	end

Lets say i = 3 ,
Is there a way to collect these 3 chosen players into a local term which can be called in a teleport function? As I am trying to teleport these specific players using CFrame, however trying to teleport ‘randPlayer’ doesn’t seem to work for me.
Hope this makes sense?

    if clonedMap:FindFirstChild("AssassainSpawns") then
    		Round.TeleportAssassains(randPlayer, clonedMap.AssassainSpawns:GetChildren())

    	else
    		warn ("Fatal error: You didn't add a spawns folder for assassains")
    	end


^This is the format of the teleport script (it calls a module function which makes it work) but when inserting randPlayer into the subject that is to be teleported it is underlined implying an error
1 Like

Maybe your problem is that assassins isn’t in an ipairs or pairs loop?

1 Like

Hi, I accidently left out a crucial top line in the code, does that change anything on what you think? (changed it now)

1 Like

For context, this code works so that I have a table of eligible players

If #eligibleplayers is 5:
I wanted 3 assassains and the rest another team

If # is 6
3 assassains 3 other team
If # is 7
4 assassains 3 other team etc up to 10

(The round module that is called I believe works as a previous team to this seems to be teleported)

1 Like

Does the actual for loop itself work? Or is the loop never called?

1 Like

There may be a problem in that you are editing the eligiblePlayers table even though you the assassins number doesn’t change.

EDIT:
Nevermind. Knowing how your code works now this doesn’t have the potential to be a problem.

Yes, I believe the players are switched to that team, however no teleport
When in the code, putting in ‘randPlayer’ to the first argument of the teleport function it results in randPlayer being underlined implying an improper term/error

1 Like

Oh! Alright so the problem you have is with scope. In the for loop where you define randPlayer, it is local. When the for loop runs it cycle, and there is a new index, randPlayer is removed. Move the teleport into the for loop and it should work.

1 Like

I thought it would? I have eligiblePlayers set up to get all players playing, and then local assassains to decide how many want to be assassains. Then, I expected the for loop to individually run through and select that number of assassains randomly, and I wanted all of these to be tped into the ap

1 Like

Look at what @WithinCode said. I believe this may be the problem, as you do not actually include any teleport function call within the loop.

Also, have you actually tested your module code to see if it works the way you intended?

1 Like

Like this?

for i = 1, assassins do
		local randIndex = math.random(#eligiblePlayers)
		local randPlayer = eligiblePlayers[randIndex]
		randPlayer.Team = teams["Assassains"]
		--remotes.DisableFootSteps:FireClient(randPlayer)
		if clonedMap:FindFirstChild("AssassainSpawns") then
			Round.TeleportAssassains(randPlayer, clonedMap.AssassainSpawns:GetChildren())

		else
			warn ("Fatal error: You didn't add a spawns folder for assassains")
		end
		table.remove(eligiblePlayers, randIndex)

You’d probably want to move the logic for finding if the spawns exist outside of the loop, and instead just use a variable for the spawns so you don’t have to go through the logic for each player, but that isn’t strictly needed for the code to work. So in short yes that would work.

2 Likes

Yes, except that depending on how your code is set up you most likely do not need to check for AssassainSpawns. If it does not exist yet instead of using :FindFirstChild it’d be better to use :WaitForChild

Also, like I mentioned earlier, use some white-box testing to see if the actual module script function itself works.

3 Likes

Going off of this, just make sure that if you do use WaitForChild if there is a chance the spawns will be created later on, by another script. Pretty much if the spawns are just a building and not spawned in by scripts, it would be more advisable to use FindFirstChild to avoid getting an infinite yield on something since the spawns would never be created.

2 Likes

Going off of this, if the spawns themselves are created by a script then it’d be advisable to wait until the map is fully loaded to set the player teams. Otherwise your code might call the error when the spawns don’t exist even though your code works and they just haven’t loaded in yet.

1 Like

For context, this is the module script that runs the tp function
Btw i do believe i have the spawns set up aswell

function module.TeleportAssassains(players, mapSpawns)

	for i, v in pairs (players) do
		if v.Character then
			local character = v.Character

			if character:FindFirstChild("HumanoidRootPart") then

				v.Character.Humanoid.WalkSpeed = 16

				local rand = Random.new()
				v.Character.HumanoidRootPart.CFrame = mapSpawns[rand:NextInteger(1,#mapSpawns)].CFrame Vector3.new(0,15,0)

			end
		end
	end
end

Something Ive done seems to have broke the code altogether so that my other team actually doesnt tp in now, il section out some code to see what doesnt work and il let you guys know. thanks for the help so far

Using what @WithinCode said, the problem does seem to be with scope. Also, because your code works using a table to loop through the players, it’d be more efficient to build a table of assassins instead and then call the function on that table. Try something like this instead:

clonedMap:WaitForChild("AssassainSpawns") -- Waits for the spawns to load in. If they haven't yet then it will yield the thread until they do. Your code should be set up in a way that it never has the opportunity to have an infinite yield.

local assassinPlayers = {} -- The players chosen to be assassins

local assassins = (#eligiblePlayers + (#eligiblePlayers % 2)) / 2
for i = 1, assassins do
	local randIndex = math.random(#eligiblePlayers)
	local randPlayer = eligiblePlayers[randIndex]

	table.insert(assassinPlayers, randPlayer)
	randPlayer.Team = teams["Assassains"]
	--remotes.DisableFootSteps:FireClient(randPlayer)

	table.remove(eligiblePlayers, randIndex)
end

Round.TeleportAssassains(assassinPlayers, clonedMap.AssassainSpawns:GetChildren())

EDIT:
Also, just a side note, since your code uses math.random it is recommended to use math.randomseed to seed the random number generator. Otherwise the numbers returned by math.random may not be as random as you like. It’s really up to personal preference though, and is unneeded. If you do want to make your code a bit more “random” though, then before the for loop you can do something like this:

math.randomseed(tick()) -- The time the moment the seed is being set can be one of the most random things to use. While you may have a time limit for a round and be able to predict how long it will last, anything can happen so you don't actually know when it will end.
2 Likes

This works! thank you both so much for your help!!! @WithinCode @BuilderBob25620

Do any of you have any idea if these types of loops may interfere with a round module? I have it so that when the game starts the players are tped from the lobby to the map, however when in game after adding these sections of code the map doesn’t switch to the roundtimer just ‘next game starting in 0’