• Adding arguments to a command made with PlayerSay
    10 replies, posted
Is there a way I could make command using the PlayerSay command that has arguments? For example doing something like this: [CODE] hook.Add("PlayerSay", "ban", function(ply, text, team) if (string.sub(text, 1,4) == "/ban") then .... target_ply:Ban( time, true ) -- target ply and ban time defined in PlayerSay hook return "" else end end) [/CODE] I'm not sure how I could make target_ply nor time an argument
[code]hook.Add("PlayerSay", "ban", function(ply, text, team) if ( string.sub( text, 1,4 ) == "/ban" ) then local strTbl = string.Explode( " ", string.sub(5)) target_ply = -- Something with strTbl[1] -- if ( target_ply ) then target_ply:Ban( tonumber( strTbl[2] ), true ) end return "" end end )[/code]
[QUOTE=code_gs;50320964][code]hook.Add("PlayerSay", "ban", function(ply, text, team) if ( string.sub( text, 1,4 ) == "/ban" ) then local strTbl = string.Explode( " ", string.sub(5)) target_ply = -- Something with strTbl[1] -- if ( target_ply ) then target_ply:Ban( tonumber( strTbl[2] ), true ) end return "" end end )[/code][/QUOTE] Would you mind explaining how this works?
[QUOTE=danker pepers;50320975]Would you mind explaining how this works?[/QUOTE] [CODE] hook.Add("PlayerSay", "ban", function(ply, txt) local text = string.Explode(" ", text) -- Take everything said and separate it where there's a space into a table if text[1] == "!ban" then -- Check if the first value in the table is "!ban" if not text[2] then return end -- If there's no 2nd value, return. local target = -- Define your target, I'm not doing that for you lol local time = tonumber(text[2]) -- Take the 2nd value in the table created above and make it a number target:Ban(time, true) -- Ban the player for the amount of time stored in the variable above return "" -- Basically so nothing appears in chat. end end) [/CODE] That should do it, sorry if I made any mistakes.
[QUOTE=danker pepers;50320975]Would you mind explaining how this works?[/QUOTE] I didn't write the code, so code_gs excuse my ninja. [URL="http://wiki.garrysmod.com/page/string/Explode"]string.Explode[/URL] takes two arguments, where the first argument is what character should be used as the "separator" character in the string. The second argument is the string to search for. Code_gs made a mistake, and should've written string.sub( text, 5 ), which would return the rest of the string past "/ban ". string.Explode then returns a table, with each listing being a string taken from the original string delimited by the space character. Forgive my ineloquence, and take this example. The string 'text' is equal to "/ban jorji 30". Calling string.Explode with the arguments " ", and string.sub( text, 5 ) will take the rest of the original string, and give you a table with the values of "jorji", and "30". Then you need to set a variable, for instance target_ply, to equal the player whose nickname corresponds with strTbl[1]. Then, call the Ban function and pass tonumber( strTbl[2] ) for the length of the ban. It appears I've been pre-emptively ninja'd. I'll leave my response incase it explains anything unclear in the above explanation.
[QUOTE=Tupac;50321043][CODE] hook.Add("PlayerSay", "ban", function(ply, txt) local text = string.Explode(" ", text) -- Take everything said and separate it where there's a space into a table if text[1] == "!ban" then -- Check if the first value in the table is "!ban" if not text[2] then return end -- If there's no 2nd value, return. local target = -- Define your target, I'm not doing that for you lol local time = tonumber(text[2]) -- Take the 2nd value in the table created above and make it a number target:Ban(time, true) -- Ban the player for the amount of time stored in the variable above return "" -- Basically so nothing appears in chat. end end) [/CODE] That should do it, sorry if I made any mistakes.[/QUOTE] Wouldn't putting local target= text[2] target the player if it was entered as a second argument? Also how could you add a reason (ignoring the fact that reason isnt an argument in ply:Ban() ) by doing something like this: [CODE] hook.Add("PlayerSay", "ban", function(ply, txt) local text = string.Explode(" ", text) -- Take everything said and separate it where there's a space into a table if text[1] == "!ban" then -- Check if the first value in the table is "!ban" if not text[2] then return end -- If there's no 2nd value, return. local target = text[2] local time = tonumber(text[3]) -- Take the 2nd value in the table created above and make it a number local reason = string.sub(text, --put something here to get the amount of characters in the first 3 table values) target:Ban(time, false ) -- Ban the player for the amount of time stored in the variable above target:Kick(reason) return "" -- Basically so nothing appears in chat. end end) [/CODE] the local reason is the line I'm asking about
[QUOTE=danker pepers;50321155]Wouldn't putting local target= text[2] target the player if it was entered as a second argument? Also how could you add a reason (ignoring the fact that reason isnt an argument in ply:Ban() ) by doing something like this: [CODE] hook.Add("PlayerSay", "ban", function(ply, txt) local text = string.Explode(" ", text) -- Take everything said and separate it where there's a space into a table if text[1] == "!ban" then -- Check if the first value in the table is "!ban" if not text[2] then return end -- If there's no 2nd value, return. local target = text[2] local time = tonumber(text[3]) -- Take the 2nd value in the table created above and make it a number local reason = string.sub(text, --put something here to get the amount of characters in the first 3 table values) target:Ban(time, false ) -- Ban the player for the amount of time stored in the variable above target:Kick(reason) return "" -- Basically so nothing appears in chat. end end) [/CODE] the local reason is the line I'm asking about[/QUOTE] text[2] is going to be a string not a player entity. You will need to go through all the players on the server and find which player has the name matching that entered into the command inorder to define the target.
[QUOTE=boxvader;50321502]text[2] is going to be a string not a player entity. You will need to go through all the players on the server and find which player has the name matching that entered into the command inorder to define the target.[/QUOTE] so do you think something like this would work? [CODE] for k, v in pairs(players.GetAll() ) do if v:Nick() == text[2] then ... [/CODE]
[QUOTE=danker pepers;50321748]so do you think something like this would work? [CODE] for k, v in pairs(players.GetAll() ) do if v:Nick() == text[2] then ... [/CODE][/QUOTE] That will only work if they type the player name exactly. May want to test to make sure their substring only matches ONE player to prevent collisions. [editline]14th May 2016[/editline] [QUOTE=jorji;50321085]I didn't write the code, so code_gs excuse my ninja. [URL="http://wiki.garrysmod.com/page/string/Explode"]string.Explode[/URL] takes two arguments, where the first argument is what character should be used as the "separator" character in the string. The second argument is the string to search for. Code_gs made a mistake, and should've written string.sub( text, 5 ), which would return the rest of the string past "/ban ". string.Explode then returns a table, with each listing being a string taken from the original string delimited by the space character. Forgive my ineloquence, and take this example. The string 'text' is equal to "/ban jorji 30". Calling string.Explode with the arguments " ", and string.sub( text, 5 ) will take the rest of the original string, and give you a table with the values of "jorji", and "30". Then you need to set a variable, for instance target_ply, to equal the player whose nickname corresponds with strTbl[1]. Then, call the Ban function and pass tonumber( strTbl[2] ) for the length of the ban. It appears I've been pre-emptively ninja'd. I'll leave my response incase it explains anything unclear in the above explanation.[/QUOTE] Oops! Thanks for catching that mistake.
[QUOTE=danker pepers;50321748]so do you think something like this would work? [CODE] for k, v in pairs(players.GetAll() ) do if v:Nick() == text[2] then ... [/CODE][/QUOTE] It's not that simple, which code_gs already addressed why. First of all the players name may contain a space in it. If they have the name "joe bob" for instance it would have been split up when we exploded the string to find the different arguments. To remedy this problem it is a good idea to ask for the players name at the very end of the command. This way if there name does contain a space we can just put it all back into 1 string. To do this we can check the size of the table using [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/table/Count]table.Count[/url]. If the size is over 3 we can then use [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/table/concat]table.concat[/url] to bring the rest of the name back to one single string. [LUA] local name = "" -- We need this declared out here if table.Count(text) > 3 then -- checking the length of the table name = table.concat(text, " ", 3, table.Count(text)) -- 3 will always be the beginning of the name and table.Count will always give the end of the name. else name = text[3] end [/LUA] Now we have the entire name if it contains spaces so we can move on to the next step in the process. We now need to check the name entered against all the names on the server to see if it matches anyone. However we need to be careful as the text entered may match 2 different people when we only want the one person. [LUA] local char = string.len(name) -- This will get us the length of the target that was entered local plySave local counter = 0 for k, v in pairs( player.GetAll() ) do local playerName = string.sub(v:GetName(), 1, strin.len) -- reducing the characters if (string.upper(name) == string.upper(playerName)) then counter = counter + 1 plySave = v end end -- Now we need to run some checks to make sure only 1 player was found and to be sure a player was found if counter = 0 then ply:PrintMessage(3, "Error: No player was found with the name " .. target) return elseif counter > 1 then ply:PrintMessage(3, "Error: There were " .. tostring(counter) .. "players found with the name" .. target) return end [/LUA] So here you can see we do a lot to check the name entered against all the players on the server. The first thing that is done is to shorten the name of the players down to the same number of characters that were entered into the command. This allows someone to only have to type a part of the players name (e.g. only typing "box" would be enough to use the command on "boxvader") making it easier for people to use the command since typing the full name can be a pain. After this is done we then set both strings to capitols, this prevents the command from being case sensitive, and compare then to see if they match. If the two strings do match we then add 1 to the counter and save the player to the save variable. The loop then continues to run through all the players if there is another match the counter will have another 1 added to it and the save variable will be overwritten. Now after the loop is finished running we need to run some checks to ensure that everything went smoothly up above. First off we want to make sure that the string actually matched to something. This is accomplished by checking to see if the counter is greater then 0. If the counter is still at 0 we send a notification to the players chat that there was an error and no players were able to be found with the name they entered. However if the counter did not remain at 0 we need to make sure that the string only matched against one other person. To do this we check to be sure the counter is not greater then 1. If the counter did surpass 1 we send a message to the player notifying them there was an error and that there was more then 1 player found with the value they supplied. That should be it, hopefully this helps you out.
[QUOTE=boxvader;50322058]It's not that simple, which code_gs already addressed why. First of all the players name may contain a space in it. If they have the name "joe bob" for instance it would have been split up when we exploded the string to find the different arguments. To remedy this problem it is a good idea to ask for the players name at the very end of the command. This way if there name does contain a space we can just put it all back into 1 string. To do this we can check the size of the table using [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/table/Count]table.Count[/url]. If the size is over 3 we can then use [img]http://wiki.garrysmod.com/favicon.ico[/img] [url=http://wiki.garrysmod.com/page/table/concat]table.concat[/url] to bring the rest of the name back to one single string. [LUA] local name = "" -- We need this declared out here if table.Count(text) > 3 then -- checking the length of the table name = table.concat(text, " ", 3, table.Count(text)) -- 3 will always be the beginning of the name and table.Count will always give the end of the name. else name = text[3] end [/LUA] Now we have the entire name if it contains spaces so we can move on to the next step in the process. We now need to check the name entered against all the names on the server to see if it matches anyone. However we need to be careful as the text entered may match 2 different people when we only want the one person. [LUA] local char = string.len(name) -- This will get us the length of the target that was entered local plySave local counter = 0 for k, v in pairs( player.GetAll() ) do local playerName = string.sub(v:GetName(), 1, strin.len) -- reducing the characters if (string.upper(name) == string.upper(playerName)) then counter = counter + 1 plySave = v end end -- Now we need to run some checks to make sure only 1 player was found and to be sure a player was found if counter = 0 then ply:PrintMessage(3, "Error: No player was found with the name " .. target) return elseif counter > 1 then ply:PrintMessage(3, "Error: There were " .. tostring(counter) .. "players found with the name" .. target) return end [/LUA] So here you can see we do a lot to check the name entered against all the players on the server. The first thing that is done is to shorten the name of the players down to the same number of characters that were entered into the command. This allows someone to only have to type a part of the players name (e.g. only typing "box" would be enough to use the command on "boxvader") making it easier for people to use the command since typing the full name can be a pain. After this is done we then set both strings to capitols, this prevents the command from being case sensitive, and compare then to see if they match. If the two strings do match we then add 1 to the counter and save the player to the save variable. The loop then continues to run through all the players if there is another match the counter will have another 1 added to it and the save variable will be overwritten. Now after the loop is finished running we need to run some checks to ensure that everything went smoothly up above. First off we want to make sure that the string actually matched to something. This is accomplished by checking to see if the counter is greater then 0. If the counter is still at 0 we send a notification to the players chat that there was an error and no players were able to be found with the name they entered. However if the counter did not remain at 0 we need to make sure that the string only matched against one other person. To do this we check to be sure the counter is not greater then 1. If the counter did surpass 1 we send a message to the player notifying them there was an error and that there was more then 1 player found with the value they supplied. That should be it, hopefully this helps you out.[/QUOTE] thank you
Sorry, you need to Log In to post a reply to this thread.