Keep in mind that I'm not trying to get facepunch to make this for me, I just need help. Basically, what I want to do is, if there are more than 2 players on the server, select a random one to be selected as a certain team, and select all the others to be on the different team I have made. I know I have to use tables and "for, k, v in pairs do" statements, but I need help...
Team 2 is called TEAM_REBEL; it's the one I need to assign a random player to.
Team 1 is called TEAM_COMBINE, that's what I want to assign the other players to.
First make a function to check if a new round should start. In this, you would check if player.GetAll is equal to or greater than two or if a round is not active (use something like not GM.InRound), and return true if both of those are true. Otherwise, return false. On PlayerInitialSpawn, call that function and if it returns true, call your new round function. In this function, define a new variable and set the value to player.GetAll. Select a random index ranging from 1 to the length of that table. Then, select the player entity at the index, set the team of the player to TEAM_REBEL, and spawn them. Next, remove the value at that index and iterate through the remaining players, assigning them to TEAM_COMBINE and spawning them. Then, set the state of the round to active. At the end of the round, set the InRound variable to false and check if a new round should start. If so, call NewRound again. If not, then there are not enough players on, and the round will start when a new player joins.
I would do something like this:
[CODE]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local Player = FindMetaTable('Player');
function Player:AutoTeamAssign()
local rebels = team.NumPlayers(TEAM_REBEL);
local combines = team.NumPlayers(TEAM_COMBINE);
if (rebels == combines) then -- If the two teams have the same amount of players
self:SetTeam(math.random( 1, 2 )); -- Assuming TEAM_REBEL is 1 and TEAM_COMBINE is 2
elseif (rebels > combines) then -- If the rebels have more players than the combines
self:SetTeam(TEAM_COMBINES);
else -- If the combines have more players than the rebels
self:SetTeam(TEAM_REBELS);
end
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then -- Checking if the round isn't started yet and if the number of players is enough to start a round.
for _, ply in pairs(player.GetAll()) do
ply:AutoTeamAssign();
end
RoundStarted = true; -- The round has now started.
end
end[/CODE]
I commented everything so you should understand it all. Notice that I didn't test it, but it should work even if it needs a lot of tweaking. Tell me if that helped you.
[QUOTE=TheKitsune;47857460]I would do something like this:
[CODE]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local Player = FindMetaTable('Player');
function Player:AutoTeamAssign()
local rebels = team.NumPlayers(TEAM_REBEL);
local combines = team.NumPlayers(TEAM_COMBINE);
if (rebels == combines) then -- If the two teams have the same amount of players
self:SetTeam(math.random( 1, 2 )); -- Assuming TEAM_REBEL is 1 and TEAM_COMBINE is 2
elseif (rebels > combines) then -- If the rebels have more players than the combines
self:SetTeam(TEAM_COMBINES);
else -- If the combines have more players than the rebels
self:SetTeam(TEAM_REBELS);
end
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then -- Checking if the round isn't started yet and if the number of players is enough to start a round.
for _, ply in pairs(player.GetAll()) do
ply:AutoTeamAssign();
end
RoundStarted = true; -- The round has now started.
end
end[/CODE]
I commented everything so you should understand it all. Notice that I didn't test it, but it should work even if it needs a lot of tweaking. Tell me if that helped you.[/QUOTE]
What I need is to assign one random player to the Rebel team and assign the rest to the Combine team. Also, Team 2 is TEAM_REBEL and Team 1 is TEAM_COMBINE. Also, don't forget that I also need that does this: Make all players who connect after the round starts(or after a person is selected to be on the Rebel team) to have their team set, upon spawn, to the Combine team.
[QUOTE=A Fghtr Pilot;47857514]What I need is to assign one random player to the Rebel team and assign the rest to the Combine team. Also, Team 2 is TEAM_REBEL and Team 1 is TEAM_COMBINE. Also, don't forget that I also need that does this: Make all players who connect after the round starts(or after a person is selected to be on the Rebel team) to have their team set, upon spawn, to the Combine team.[/QUOTE]
Well, you didn't say that last part there, but all you have to do is check if the round is active and assign them to the team. Really not too difficult.
I think I'm not understanding you properly, you want ONE player in the rebel team for the whole game?
[QUOTE=TheKitsune;47857538]I think I'm not understanding you properly, you want ONE player in the rebel team for the whole game?[/QUOTE]
If you mean "whole game" as in "the whole round" then yes. If not, no.
Then this should fit your needs:
[CODE]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local function PickRandomRebel()
Player(math.random(1, #player.GetAll())):SetTeam(TEAM_REBEL)
end
local function StartRound()
PickRandomRebel()
for _, ply in pairs(player.GetAll()) do
if (ply:Team() != TEAM_REBEL) then
ply:SetTeam(TEAM_COMBINE)
end
end
RoundStarted = true;
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then
StartRound();
end
end
function GM:PlayerIntialSpawn(ply)
if (RoundStarted) then
ply:SetTeam(TEAM_COMBINE)
end
end[/CODE]
Call StartRound whenever you want to start a new round.
This is untested and not tweaked but it should work, I hope that this time, it is what you asked for. Tell me if this works for you.
[editline]2nd June 2015[/editline]
Invule: You "disagree" with the code, ok, but why? I know it's messy and not tweaked at all. But it was just to give an example. Give us an insight on why it's bad, it will help more than just a rating.
I actually made a mistake in my last code that would add a new rebel each round instead of picking a new one, here is the fixed code (still not tested):
[CODE]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local function PickRandomRebel()
Player(math.random(1, #player.Getall())):SetTeam(TEAM_REBEL) -- We pick a player with a random index and then set him as the rebel
end
local function StartRound()
-- We reset all players to be combines
for _, ply in pairs(player.GetAll()) do
ply:SetTeam(TEAM_COMBINE)
end
PickRandomRebel() -- Then one of them is picked to be the rebel
RoundStarted = true; -- The round has now started
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then -- If the round isn't started yet and that there is enough player to start one
StartRound(); -- Then we start the round
end
end
function GM:PlayerIntialSpawn(ply)
if (RoundStarted) then -- If the round has started
ply:SetTeam(TEAM_COMBINE) -- We set our joining player team to combine
end
end[/CODE]
I hope it helped you.
[code]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local function PickRandomRebel()
Player(math.random(1, #player.GetAll())):SetTeam(TEAM_REBEL)
end
local function StartRound()
PickRandomRebel()
for _, ply in pairs(player.GetAll()) do
ply:Spawn()
if (ply:Team() != TEAM_REBEL) then
ply:SetTeam(TEAM_COMBINE)
player_manager.SetPlayerClass( ply, "player_combine" )
elseif (ply:Team() == TEAM_REBEL) then
player_manager.SetPlayerClass( ply, "player_rebel" )
end
end
RoundStarted = true;
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then
StartRound();
end
end
function GM:PlayerInitialSpawn(ply)
timer.Simple( 0, function()
if (RoundStarted) then
player_manager.SetPlayerClass( ply, "player_combine" )
ply:SetTeam(TEAM_COMBINE)
end
end)
end
function GM:PlayerSpawn(ply)
player_manager.OnPlayerSpawn()
player_manager.RunClass( ply, "Loadout" )
player_manager.RunClass( ply, "SetModel" )
end
[/code]
I've added in some stuff, this is what I'll use
I think that there are some stuff in you code that are just wrong:
First of all:
[CODE]timer.Simple( 0, function()[/CODE]
Why? I can't see why you need this timer.
[CODE]player_manager.RunClass( ply, "Loadout" )
player_manager.RunClass( ply, "SetModel" )[/CODE]
I'm pretty sure this is not required as the wiki says "Called on spawn to give the player their default loadout", it means this will automatically be called (see [url]http://wiki.garrysmod.com/page/PLAYER/SetModel[/url] and [url]http://wiki.garrysmod.com/page/PLAYER/Loadout[/url])
Your code is not tweaked at all:
[CODE]elseif (ply:Team() == TEAM_REBEL) then
player_manager.SetPlayerClass( ply, "player_rebel" )
end[/CODE]
Making this elseif is useless. Plus, I just noticed you were using my unfixed code. As you call PickRandomRebel() before the for loop. Here is the code you need, a little bit more tweaked:
[CODE]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local Player = FindMetaTable('Player')
function Player:JoinRebel()
ply:SetTeam(TEAM_REBEL)
player_manager.SetPlayerClass( self, "player_rebel" )
end
function Player:JoinCombine()
ply:SetTeam(TEAM_REBEL)
player_manager.SetPlayerClass( self, "player_rebel" )
end
local function PickRandomRebel()
local ply = Player(math.random(1, #player.GetAll()));
ply:JoinRebel()
end
local function StartRound()
for _, ply in pairs(player.GetAll()) do
ply:Spawn()
ply:JoinCombine()
end
PickRandomRebel()
RoundStarted = true;
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then
StartRound();
end
end
function GM:PlayerInitialSpawn(ply)
if (RoundStarted) then
ply:JoinCombine()
end
end[/CODE]
Moreover, avoid repeating you code that much, you used "player_manager.SetPlayerClass( ply, "player_combine" ); ply:SetTeam(TEAM_COMBINE)" twice, in that case, just make a function that does the two, this makes the code cleaner. I hope it helped you.
[QUOTE=TheKitsune;47861399]I think that there are some stuff in you code that are just wrong:
First of all:
[CODE]timer.Simple( 0, function()[/CODE]
Why? I can't see why you need this timer.
[CODE]player_manager.RunClass( ply, "Loadout" )
player_manager.RunClass( ply, "SetModel" )[/CODE]
I'm pretty sure this is not required as the wiki says "Called on spawn to give the player their default loadout", it means this will automatically be called (see [url]http://wiki.garrysmod.com/page/PLAYER/SetModel[/url] and [url]http://wiki.garrysmod.com/page/PLAYER/Loadout[/url])
Your code is not tweaked at all:
[CODE]elseif (ply:Team() == TEAM_REBEL) then
player_manager.SetPlayerClass( ply, "player_rebel" )
end[/CODE]
Making this elseif is useless. Plus, I just noticed you were using my unfixed code. As you call PickRandomRebel() before the for loop. Here is the code you need, a little bit more tweaked:
[CODE]local RoundStarted = false; -- Has the round started
local MinPlayers = 2; -- The minimum amount of players to start a round
local Player = FindMetaTable('Player')
function Player:JoinRebel()
ply:SetTeam(TEAM_REBEL)
player_manager.SetPlayerClass( self, "player_rebel" )
end
function Player:JoinCombine()
ply:SetTeam(TEAM_REBEL)
player_manager.SetPlayerClass( self, "player_rebel" )
end
local function PickRandomRebel()
local ply = Player(math.random(1, #player.GetAll()));
ply:JoinRebel()
end
local function StartRound()
for _, ply in pairs(player.GetAll()) do
ply:Spawn()
ply:JoinCombine()
end
PickRandomRebel()
RoundStarted = true;
end
function GM:Think()
if (!RoundStarted && #player.GetAll() >= MinPlayers) then
StartRound();
end
end
function GM:PlayerInitialSpawn(ply)
if (RoundStarted) then
ply:JoinCombine()
end
end[/CODE]
Moreover, avoid repeating you code that much, you used "player_manager.SetPlayerClass( ply, "player_combine" ); ply:SetTeam(TEAM_COMBINE)" twice, in that case, just make a function that does the two, this makes the code cleaner. I hope it helped you.[/QUOTE]
Actually, I NEED that timer, as PlayerInitialSpawn is called in the loading screen. Making a timer(doesn't matter how long) in PlayerInitialSpawn waits for the player to actually spawn.
Also, I need my PlayerSpawn hook, as if I don't call player_manager.RunClass and player_manager.OnPlayerSpawn then certain aspects I need for my classes won't be activated(or whatever word I'm looking for).
Also if someone types "lua_run JoinRebels()" in the console their can be more than one rebel(which I don't want).
I have never seen that or heard that it was required to have a timer in PlayerInitialSpawn, and I've never needed one. have you tried without the timer? I know that it's called while sending the client's info, but I already used player_manager.SetPlayerClass in this hook without timer and I had no problems. Or just use the PlayerSpawn hook:
[CODE]function GM:PlayerSpawn(ply)
if (RoundStarted && ply:Team != TEAM_REBEL) then
ply:JoinCombine();
end
end[/CODE]
This feels less hacky than your timer method. As for the rest, I think you should apply it.
[editline]2nd June 2015[/editline]
They can't do lua_run if you put it serverside.
[code]--Line 92: local ply = Player(math.random(1, #player.GetAll()));[/code]
[code][ERROR] addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:92: attempt to call upvalue 'Player' (a table value)
1. PickRandomRebel - addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:92
2. StartRound - addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:98
3. unknown - addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:113
[/code]
So, just to explain it more clearly to you (as I was in a hurry before):
- Clients won't be able to do "lua_run JoinRebels()", as it is SERVER SIDE, this means the clients can't have access to them. This also means that making functions server side is SAFE;
- I'm pretty sure that "player_manager.SetPlayerClass" can be called without any issue in the hook "InitialPlayerSpawn", and so should SetTeam. The major problem with this hook is for getter functions, as for "GetModel" as not everything is set for the players;
- If you already need your "PlayerSpawn" hook, then just use the hook library, with hook.Add (see [url]http://wiki.garrysmod.com/page/hook/Add[/url])
- There must be something wrong if you are forced to call "player_manager.OnPlayerSpawn", are you sure your gamemode is derived from the base gamemode? You should (re)read the gamemode creation basics on the wiki ([url]http://wiki.garrysmod.com/page/Gamemode_Creation[/url]).
I just got an error. I need help... It's posted above.
Oh, for that problem, try to replace
[CODE]local Player = FindMetaTable('Player')[/CODE]
With
[CODE]local MetaPly = FindMetaTable('Player')[/CODE]
And this
[CODE]function Player:JoinRebel()[/CODE]
With
[CODE]function MetaPly:JoinRebel()[/CODE]
And finally this
[CODE]function Player:JoinCombine()[/CODE]
With
[CODE]function MetaPly:JoinCombine()[/CODE]
[editline]2nd June 2015[/editline]
Yeah you ninja'd me, and a "Please" sometimes, it can't hurt.
What?! function MetaPly:JoinRebel()
self:SetTeam( 2 )
player_manager.SetPlayerClass( self, "player_rebel" )
end is a nil value? [ERROR] addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:94: attempt to call method 'JoinRebel' (a nil value)
1. PickRandomRebel - addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:94
2. StartRound - addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:98
3. unknown - addons/rebelsvscombine/gamemodes/therebel/gamemode/init.lua:113
[editline]2nd June 2015[/editline]
local function PickRandomRebel()
local ply = Player(math.random(1, #player.GetAll()));
ply:JoinRebel()
end
I don't know, I don't have the time right now. And I'm getting a bit tired of helping for nearly two days without seeing a single "thanks" or even knowing if you even followed what I told you. I'll check later for your error, it could come from the Player function or something.
[editline]2nd June 2015[/editline]
And if you modified the code I gave you, at least post it if you want anyone to be able to fix it.
I also like how you said you didn't want anyone to make it for you yet that's what poor Kitsune is actually doing. Also, please stop spamming this section with your endless amounts of questions and use the "Problems that don't need their own thread" thread for them instead.
Spamming? Sorry... Anyways I ended up making my own round system that works perfectly now... I based it off of ideas I got from here. Thanks for the help AK to spray and TheKitsune(not sarcasm)!
Sorry, you need to Log In to post a reply to this thread.