How to run a function when you press a Derma button

How do you run a function without adding a console command to it. I’m trying to make a function where it changes your team but I don’t want players to be able to run the function unless they press a derma button.

Heres what I got so far:
[LUA]
– Change the players Team and is Serverside
function Test( ply )
if ply:Team() == 2 then
ply:PrintMessage( HUD_PRINTTALK, “Testing”) else
ply:SetTeam( 2 )
ply:Spawn()
end
end
[/LUA]

[LUA]
– Panel
function TestMenu()

gui.EnableScreenClicker( true )
local frame = vgui.Create( “DFrame” )
frame:SetSize( 450, 450 )
frame:Center()
frame:SetTitle( “Menu” )
frame:ShowCloseButton( true )

local SheetItemOne = vgui.Create( “DPanel” )
SheetItemOne:SetParent( frame )
SheetItemOne:SetSize( 430, 410 )
SheetItemOne:SetPos( 10, 30 )
SheetItemOne.Paint = function()
surface.SetDrawColor( 50, 50, 50, 255 )
surface.DrawRect( 0, 0, SheetItemOne:GetWide(), SheetItemOne:GetTall() )
end

button = vgui.Create( “DButton” )
button:SetText( “Testing” )
button:SetPos( 200, 75 )
button:SetSize( 200, 50 )
button:SetParent( frame )
button.DoClick = function( ply )
function Test()
gui.EnableScreenClicker( false )
frame:Close()
end
end

end

concommand.Add(“Testing”, TestMenu)
[/LUA]

I thought this is how you do it, but when I press the derma button nothing happens and the frame doesn’t close.
Any help solving this problem would be appreciated.

That’s because your just declaring another function when you click, and not calling any function.
Since you recreate the panel every time, just use Remove() so it should look like this.

[LUA]
function TestMenu()

gui.EnableScreenClicker( true )
local frame = vgui.Create( “DFrame” )
frame:SetSize( 450, 450 )
frame:Center()
frame:SetTitle( “Menu” )
frame:ShowCloseButton( true )

local SheetItemOne = vgui.Create( “DPanel” )
SheetItemOne:SetParent( frame )
SheetItemOne:SetSize( 430, 410 )
SheetItemOne:SetPos( 10, 30 )
SheetItemOne.Paint = function()
surface.SetDrawColor( 50, 50, 50, 255 )
surface.DrawRect( 0, 0, SheetItemOne:GetWide(), SheetItemOne:GetTall() )
end

button = vgui.Create( “DButton” )
button:SetText( “Testing” )
button:SetPos( 200, 75 )
button:SetSize( 200, 50 )
button:SetParent( frame )
button.DoClick = function()
Test()
frame:Remove()
end
end
[/LUA]

But the function Test() is a serverside function, or it least that is where your supposed to have it. So your going to have to call a concommand, so on the server side it should look like this.

[LUA]
local function Demo(Player, cmd, args)
if Player:Team() == 2 then
Player:PrintMessage( HUD_PRINTTALK, “Testing”)
else
Player:SetTeam( 2 )
Player:Spawn()
end
end
concommand.Add(“DemoCmd”, Demo)
[/LUA]

But then your button click should look like this.

[LUA]
button.DoClick = function()
RunConsoleCommand(“DemoCmd”)
frame:Remove()
end
[/LUA]

Is there any way to make it so that the console command can only be run when the player presses the Derma button? With the code right now couldn’t the player just type DemoCmd in console and change teams?

You can use datastream, but even that can be bypassed, especially if you have scriptenforcer turned off.

Short answer: No. But you can pass some info as an argument (Such as a CRC of a string, unique identifier of some kind) to prevent 99% of people from exploiting it

Okay, I appreciate the help from both of you.

[editline]13th January 2011[/editline]

Okay, thanks for the input also, I’ll look into that in a little bit.

Usually your gamemode or whatever should have checks on the player to make sure he is allowed to change the team, so you would check before you let him switch teams. Like if he’s alivem if it’s been long enough since his last switch, or if the teams are balanced.