Simple Gamemode

From GMod Wiki

Jump to: navigation, search
Lua: Basic Gamemode with Basic Functions
Page white text.png Description:Simple Gamemode, intended to help people learn Lua and how to make a Gamemode.
link=User:Darkcha0s Original Author:Darkcha0s
Calendar.png Created:11th April, 2009

Contents


The beginning

Foreword

If you're like me, you're probably a lonely straggler, who feels he will never be able to shoot for the Moon. (Get the reference to Lua? Lua = Moon) Anyways, I know I'm not funny, but I do hope I can help you learn a little bit today. I'll start this as the first part in my little tutorial series. I found for myself, the easiest thing for me, to learn Lua, was to start difficult, and once you master it, everything else becomes clear. You might not be this type of learner, but this tutorial will help you anyways, since it teaches basic concepts on how to create a Gamemode you can call your own.

Let me start at this point, by saying we aren't creating another TacoScript, Cakescript or anything close to those. With this base it would be fairly difficult to derive it all that way. Don't get your hopes too high, you are infact probably still a beginner, but we all once were.

Without further blabbering, let's begin.


Starting your Gamemode

Before we jump right in let's establish what every Gamemode needs to have.

Program Files/steam/steamapps/%username%/garrysmod/garrysmod/gamemodes/Your Gamemode

One thing that I usually push towards a clean work environment. I choose to use Notepad++, but this is always up to you. Anyways, let's start by going in the Gamemodes folder and creating our gamemode folder. I named ours SimpleBuild. Within this folder create another folder entitled gamemode. This is where your actual gamemode will be inside. Here is what it should look like:


Heirarchy.png

Assuming that's done let's open our Notepad++. I went ahead and opened three tabs, one for:


You're probably asking yourself what those are? Well simply put, init.lua is responsible for the server side of things, cl_init.lua for the clientside of things and shared.lua for, you guessed it, both. What appears to be complex and totally confusing, actually is quite easy to grasp. I'll come back to that later though.

Lame I know, now let's start with some code.

I'll handle it this way, first I start with what both need, then server, then client.


Now the ball's rolling

Shared.lua

I'll repeat myself saying this file contains the code which is used both client and server side. For our gamemode this file will actually be rather short, however it will contain vital information needed.

 
GM.Name		= "SimpleBuild" //What is your Gamemode's name?
GM.Author	= "Darkcha0s" // Who authored it?
GM.Email	= "[email protected]" //Your email?
GM.Website      = "thec0re.net" //Website, only if you feel it
 

So far so good, the green things behind the // are comments. These are not read by Garry's Mod and have no effect on your code. Assuming I commented that well, you should see how basic some Lua code really is.

Next is a crucial step for any simple gamemode. Deriving. While this deriving is not as complicated as the one you do in calculus, it's just as needed. Without deriving you're missing most basic functions which are found in your sandbox gamemode, kindly premade by Garry himself. For this we do:

 
DeriveGamemode( "sandbox" )
 

Again that was not at all hard.

Now we have the little how I call it, header, finished. From now on this file only contains repetitive code. What this code is? Oh, probably the most important part. The teams. You want to differentiate different players by class, this is capitalism not god damn socialism. This far not as complicated or as fucked up as any economy, much more it's easy and overviewable. I'll go ahead and give you the code here:

 
team.SetUp( 1, "Guest", Color( 125, 125, 125, 255 ) ) //Team guest
team.SetUp( 2, "Admin", Color( 255, 255, 255, 255 ) ) //Team admin
team.SetUp( 3, "Darkcha0s", Color( 148, 0, 211, 255 ) ) //It's not me!  
team.SetUp( 4, "Joining", Color( 0, 0 , 0, 255 ) ) //Joining
 

You can grasp the basics.

That would be it for shared.lua!

Init.lua

Welcome to the beast. This code in most gamemodes will probably be the longest and most complicated, and will provide the most headaches. But hey, not for us, we know how to do this!

First off, we are telling the client what files this gamemode has which need to be downloaded, a.k.a every file of your gamemode. Again this is quite simple code.

 
AddCSLuaFile( "cl_init.lua" ) //dl that
AddCSLuaFile( "shared.lua" ) //dl that too
AddCSLuaFile( "specialchars.lua" ) //and this
 

Now the client has the file, but it's just sitting in his /lua folder. Quite useless I'd say. For init.lua we don't need to include cl_init.lua, because the server side can't execute clientside code, making useless. What does include mean? It means include that lua file in this lua file so we can use it's functions in this file. I hope that's not too complicated, re-read it a couple of times to understand it perfectly. That being said, let's include.

 
include( 'shared.lua' ) //load that
include( 'specialchars.lua' ) //This too.
 

Now we have all those functions from those files, (I'll get to specialchars.lua later) in this file right here. We can call on them et cetera.

Like with Shared.lua we are now done with what I call the header, the stuff that is just given code that doesn't have any direct functions for your gamemode.

First off, Garry's Sandbox gamemode is not perfect. There is a well known error in it, which will give you an error around line 40. I don't recall what it was, but we don't need to know that, because guess what- I have a workaround. Without much explanation, put this in the code now.

 
-- What happens when a player spawns
function GM:PlayerSpawn( ply )
    self.BaseClass:PlayerSpawn( ply )   
 
    ply:SetGravity  ( 0.75 )  -- Although I suggest 1, becuase .75 is just too low.
    ply:SetMaxHealth( 100, true )  
 
    ply:SetWalkSpeed( 325 )  
    ply:SetRunSpeed ( 325 ) 
 
end
 

For the record, GM:PlayerSpawn( ply ) means this happens every time the player spawns. Be it the first spawn, the spawn after he dies, or his last spawn. The code inside it simply sets his gravity, max health, et cetera, you can read it out of there.

Assuming so far you aren't all too lost lets begin with the first complex piece of code so far. Our GM:PlayerInitialSpawn. What this does? Well simply put, it's code that's executed the first time he spawns on joining the server. It will only execute that one time, and not again, unless you call on it again.

Here it is:

 
function GM:PlayerInitialSpawn( ply )  // When spawning after joining the sever
	CheckSpecialCharacters( ply ) //Is he defined in the specialchars.lua file? If yes, then he gets those values, and it stops here.
	if ply:IsAdmin() then //Is the connecting player admin?
		sb_team2( ply ) //If he is then set his team to team 2.
	else // If he isn't admin then,
	joining( ply ) //Call the function joining (found near the bottom of this file)
	RunConsoleCommand( "sb_start" )	 //Run the console command defined in cl_init.lua. 
	end //Close the if
end //close the function
 

The comments say it pretty well, but here it is again.

sb_team2( ply ). This runs the function which is a bit lower in this file, I'll come back to it.

Now we have the top level function complete. Let's get into what happens behind the scene.

Firstly, the player needs a loadout, I hope you would agree. Unless you want him to run around with nothing, spawning random props, you will follow what I do next. We use the function GM:PlayerLoadout to give the player his load out.

 
function GM:PlayerLoadout( ply ) // What should the player recieve when joining a team?
 
	if ply:Team() == 1 then //If he is team 1, then give him the following items
 
		ply:Give( "weapon_physcannon" ) // A Gravity gun
		ply:Give( "weapon_physgun" ) // A Physics gun
		ply:Give( "gmod_tool" ) // and don't forget the tool gun!
 
 
	elseif ply:Team() == 2 then // So if he isn't team 1, he could be team 2?
 
		ply:Give( "weapon_physcannon" ) //Assuming he is, then give him Gravity gun
		ply:Give( "weapon_physgun" ) // Physics gun
		ply:Give( "weapon_ar2" ) // AR2 
		ply:Give( "gmod_tool" ) // and the gmod tool
 
	//I should mention at this point you can put in else, but there is no point. All possible scenarios are covered. Thus we end it	
	end //right here.
end // End the function
 

I'll do it step by step again.

Alright, that was quite easy to grasp, wasn't it? I hope it was. Now we are basically in the clear. Just 3 more functions.

The first one is that we have a function, as to what happens when the player is set to join team 1. This function name is what ever you wish. Easy isn't it?

 
function sb_team1( ply ) //This is what happens when we enter sb_team1 into the console.
 
	ply:UnSpectate() //Since he was set to spectate until he presses the 'hell yeah' button, we now unspecatate him
	ply:SetTeam( 1 ) //We set his team to one, a.k.a 'guest'
	ply:Spawn() //Spawn the player
	ply:PrintMessage( HUD_PRINTTALK, "[SimpleBuild]Welcome to the server, " .. ply:Nick() ) //Gives the message [SimpleBuild]Welcome to the server, (playername here)"  in the talk area.
 
end //End the function.
 

Here is what we did;

Now, team 1 is handled. Team 2 is now up, which is the admin team if you remember out InitialSpawn function.

Here is that code;

 
function sb_team2( ply ) // Function sb_team2. Called at the beginning
	// Why no unspectate? Look carefully at the GM:PlayerSpawn; We only call to spectate after we see if he's an admin. Assuming he's always ready to build, I chose to skip it.	
	ply:SetTeam( 2 ) //Set his team to team 2.
	ply:Spawn() // Spawn him
	ply:PrintMessage( HUD_PRINTTALK, "[SimpleBuild]I recognize you as an admin, " .. ply:Nick() ) //Again, a message in the talk area. 
	//This time saying "[SimpleBuild] I recognize you as an admin (playername here)" 
 
end //End this function
 

Now we add a console command. This is very important otherwise the players can't play. PUT THIS CODE IN, IT'S CRUCIAL.

 
concommand.Add( "sb_team1", sb_team1 ) //Now, we make sure that when we enter sb_team1 into console that it calls the function. This is KEY. Otherwise players won't be able to play.
 

We add the console command sb_team1 which runs the function sb_team1. We call on this console command in cl_init.lua. Console commands are the easiest way for these files in to interact with each other.

Finally, the last function.

 
function joining( ply ) // The function that's called when the player is not admin or a special character, at the top.
 
	ply:Spectate( 5 ) //Set him to spectate in free-roam mode. He doesn't actually fly around, since he has a window open at this point.
	ply:SetTeam( 4 ) //Set his team to Joining
 
end //End the function
 

This was called in the intialspawn. If it's a simple player, he first runs this function, which;

Remember how in the sb_team1 function I unspectate him? I specatated him here, so I must undo it there.

We are done with init.lua! What a beast!

cl_init.lua

This is no different then the others, we start with the 'header'. This time we only include shared, since it doesn't call on any other functions.

 
include( 'shared.lua' ) //LOAD THAT
 

Simple enough.

Now to this part. What I chose to do, is if the player is not admin or a special character, he has to press a button, saying he is ready to build. Why I do this? For fun. This uses vgui, a concept only present on the client side, hence it's in the cl_init. It's one function, but quite a long one, so bare with me.

 
function set_team() //Function for the window when joining as neither special character nor Admin
 
Ready = vgui.Create( "DFrame" ) //Define ready as a "DFrame"
Ready:SetPos( ScrW() / 2, ScrH() / 2 ) //Set the position. Half the screen height and half the screen width. This will result in being bottom right of the middle of the screen.
Ready:SetSize( 175, 75 ) //The size, in pixels of the Frame
Ready:SetTitle( "Are you ready to build?" ) //The title; It's at the top.
Ready:SetVisible( true ) // Should it be seen? 
Ready:SetDraggable( false ) // Can people drag it around?
Ready:ShowCloseButton( false ) //Show the little X top right? I chose no, because I have no alternative, meaning people would roam around with no weapons
Ready:MakePopup() //Make it popup. Of course.
 

Basically, we open a function, called set_team, then define Variable Ready as a DFrame, a simple frame. Assuming you can read (I do hope so), you can grasp code beneath it. We simply define some things for the frame, such as size, location, title, et cetera.

Notice it's not closed yet. Because it's not done! Now we add a button.

 
ready1 = vgui.Create( "DButton", Ready ) // Define ready1 as a "DButton" with its parent the Ready frame we just created above.
ready1:SetPos( 20, 25 ) //Set position, relative to the frame (If you didn't parent it, it would be relative to the screen
ready1:SetSize( 140, 40 ) // How big it should be, again in pixels
ready1:SetText( "Hell yeah!" ) //What should the button say? 
ready1.DoClick = function() //ready1.doclick = function, we just defined it as a function
RunConsoleCommand( "sb_team1" ) //When it clicks, which function does it run? sb_team1, which is defined in init.lua
 
end // end the doclick function
 
end // end the set_team function
 

So now ready1 is defined as a DButton. Notice behind DButton is says Ready? It's because it's parent is the ready frame, making everything defined relative to it. Again it's defined, but now notice one difference- DoClick. This basically says, when it's click run a function. When it's clicked, it runs the console command, sb_team1, which we defined in init.lua- Using RunConsoleCommand.

Remember how we ran at GM:IntialSpawn Set_Team? Well that's this function, hence we must add it as a console command.

 
concommand.Add( "sb_start", set_team ) //Now we add a console command for the function we just created. It can be run straight from the console. If you look under the first couple of lines under init.lua, we
// said that it should run this command!
 

Then we end the button and the function.

That's it for cl_init!

The basic Gamemode runs

What's missing

As promised, you now have a fully working gamemode. But what would a gamemode be without you abusing your status 24/7? Exactly, really lame for you. So let's make a file which allows us to add our own characters!

Specialchars.lua

If you recall GM:IntitialSpawn, you will remember I called on the function checkspecial characters. Here is where I define it. The code is straight forward, and well commented.

 
function CheckSpecialCharacters( ply ) //This function is called upon on GM:PlayerInitialSpawn
 
 
//Here we add our characters which are special.
//I left an example with what I have
 
	--Darkcha0s
	if ( ply:SteamID() == "STEAM_0:1:7880281" ) then //If steamid is that, then execute the following
 
		ply:PrintMessage( HUD_PRINTTALK, "Welcome back, " .. ply:Nick() .. "\nYou connected under the IP: " .. ply:IPAddress() ) // Gives the message
		//Welcome back Darkcha0s, you have connected under the IP: blah. In local multiplayer it will be loopback.
		ply:SetTeam( 3 ) //Set it to this team, look in shared.lua for this one.
		// He should recieve the following weapons
		ply:Give( "weapon_crowbar" )
		ply:Give( "weapon_pistol" )
		ply:Give( "weapon_smg1" )
		ply:Give( "weapon_frag" )
		ply:Give( "weapon_physcannon" )
		ply:Give( "weapon_crossbow" )
		ply:Give( "weapon_shotgun" )
		ply:Give( "weapon_357" )
		ply:Give( "weapon_rpg" )
		ply:Give( "weapon_ar2" )
		ply:Give( "gmod_tool" )
	    ply:Give( "gmod_camera" )
	    ply:Give( "weapon_physgun" )
	end //end this if
	//For other characters, use elseif for example
	// elseif (ply:SteamID() == "STEAM 02984529" ) then 
	//ply:SetTeam( 2 ) 
	//etc. etc.
end //end the function
 

And we're done! Your character is defined, and when you go on, you will recieve everything you want.

Overview

Here's all the code for you.

 
GM.Name		= "SimpleBuild" //What is your Gamemode's name?
GM.Author	= "Darkcha0s" // Who authored it?
GM.Email	= "[email protected]" //Your email?
GM.Website  = "thec0re.net" //Website, only if you feel it
DeriveGamemode( "sandbox" ) //Derive from Sandbox. If you want the Q menu's and Garry's scoreboard, keep this.
 
team.SetUp( 1, "Guest", Color( 125, 125, 125, 255 ) ) //Team guest
team.SetUp( 2, "Admin", Color( 255, 255, 255, 255 ) ) //Team admin
team.SetUp( 3, "Darkcha0s", Color( 148, 0, 211, 255 ) ) //It's me!  
team.SetUp( 4, "Joining", Color( 0, 0 , 0, 255 ) ) //Joining
 
 
AddCSLuaFile( "cl_init.lua" ) //dl that
AddCSLuaFile( "shared.lua" ) //dl that too
AddCSLuaFile( "specialchars.lua" ) //and this
 
 
include( 'shared.lua' ) //load that
include( 'specialchars.lua' ) //This too.
 
 
function GM:PlayerSpawn( ply )  //What happens when the player spawns
 
    self.BaseClass:PlayerSpawn( ply )   // Lines 12 through 18 are all fixes to the sandbox glitch. Don't change
										// them unless you know what you're doing.
    ply:SetGravity( 0.75 )  
    ply:SetMaxHealth( 100, true )  
 
    ply:SetWalkSpeed( 325 )  
	ply:SetRunSpeed( 325 ) 
 
end
 
function GM:PlayerInitialSpawn( ply )  // When spawning after joining the sever
	CheckSpecialCharacters( ply ) //Is he defined in the specialchars.lua file? If yes, then he gets those values, and it stops here.
	if ply:IsAdmin() then //Is the connecting player admin?
		sb_team2( ply ) //If he is then set his team to team 2.
	else // If he isn't admin then,
	joining( ply ) //Call the function joining (found near the bottom of this file)
	RunConsoleCommand( "sb_start" )	 //Run the console command defined in cl_init.lua. 
	end //Close the if
end //close the function
 
 
function GM:PlayerLoadout( ply ) // What should the player recieve when joining a team?
 
	if ply:Team() == 1 then //If he is team 1, then give him the following items
 
		ply:Give( "weapon_physcannon" ) // A Gravity gun
		ply:Give( "weapon_physgun" ) // A Physics gun
		ply:Give( "gmod_tool" ) // and don't forget the tool gun!
 
 
	elseif ply:Team() == 2 then // So if he isn't team 1, he could be team 2?
 
		ply:Give( "weapon_physcannon" ) //Assuming he is, then give him Gravity gun
		ply:Give( "weapon_physgun" ) // Physics gun
		ply:Give( "weapon_ar2" ) // AR2 
		ply:Give( "gmod_tool" ) // and the gmod tool
 
	//I should mention at this point you can put in else, but there is no point. All possible scenarios are covered. Thus we end it	
	end //right here.
end // End the function
 
function sb_team1( ply ) //This is what happens when we enter sb_team1 into the console.
 
	ply:UnSpectate() //Since he was set to spectate until he presses the 'hell yeah' button, we now unspecatate him
	ply:SetTeam( 1 ) //We set his team to one, a.k.a 'guest'
	ply:Spawn() //Spawn the player
	ply:PrintMessage( HUD_PRINTTALK, "[SimpleBuild]Welcome to the server, " .. ply:Nick() ) //Gives the message [SimpleBuild]Welcome to the server, (playername here)"  in the talk area.
 
end //End the function.
 
 
function sb_team2( ply ) // Function sb_team2. Called at the beginning
	// Why no unspectate? Look carefully at the GM:PlayerSpawn; We only call to spectate after we see if he's an admin. Assuming he's always ready to build, I chose to skip it.	
	ply:SetTeam( 2 ) //Set his team to team 2.
	ply:Spawn() // Spawn him
	ply:PrintMessage( HUD_PRINTTALK, "[SimpleBuild]I recognize you as an admin, " .. ply:Nick() ) //Again, a message in the talk area. 
	//This time saying "[SimpleBuild] I recognize you as an admin (playername here)" 
 
end //End this function
concommand.Add( "sb_team1", sb_team1 ) //Now, we make sure that when we enter sb_team1 into console that it calls the function. This is KEY. Otherwise players won't be able to play.
 
function joining( ply ) // The function that's called when the player is not admin or a special character, at the top.
 
	ply:Spectate( 5 ) //Set him to spectate in free-roam mode. He doesn't actually fly around, since he has a window open at this point.
	ply:SetTeam( 4 ) //Set his team to Joining
 
end //End the function
 
 
include( 'shared.lua' ) //LOAD THAT
 
function set_team() //Function for the window when joining as neither special character nor Admin
 
Ready = vgui.Create( "DFrame" ) //Define ready as a "DFrame"
Ready:SetPos( ScrW() / 2, ScrH() / 2 ) //Set the position. Half the screen height and half the screen width. This will result in being bottom right of the middle of the screen.
Ready:SetSize( 175, 75 ) //The size, in pixels of the Frame
Ready:SetTitle( "Are you ready to build?" ) //The title; It's at the top.
Ready:SetVisible( true ) // Should it be seen? 
Ready:SetDraggable( false ) // Can people drag it around?
Ready:ShowCloseButton( false ) //Show the little X top right? I chose no, because I have no alternative, meaning people would roam around with no weapons
Ready:MakePopup() //Make it popup. Of course.
 
ready1 = vgui.Create( "DButton", Ready ) // Define ready1 as a "DButton" with its parent the Ready frame we just created above.
ready1:SetPos( 20, 25 ) //Set position, relative to the frame (If you didn't parent it, it would be relative to the screen
ready1:SetSize( 140, 40 ) // How big it should be, again in pixels
ready1:SetText( "Hell yeah!" ) //What should the button say? 
ready1.DoClick = function() //ready1.doclick = function, we just defined it as a function
RunConsoleCommand( "sb_team1" ) //When it clicks, which function does it run? sb_team1, which is defined in init.lua
 
end // end the doclick function
 
end // end the set_team function
 
concommand.Add( "sb_start", set_team ) //Now we add a console command for the function we just created. It can be run straight from the console. If you look under the first couple of lines under init.lua, we
// said that it should run this command!
 
 
function CheckSpecialCharacters( ply ) //This function is called upon on GM:PlayerInitialSpawn
 
 
//Here we add our characters which are special.
//I left an example with what I have
 
	--Darkcha0s
	if ( ply:SteamID() == "STEAM_0:1:7880281" ) then //If steamid is that, then execute the following
 
		ply:PrintMessage( HUD_PRINTTALK, "Welcome back, " .. ply:Nick() .. "\nYou connected under the IP: " .. ply:IPAddress() ) // Gives the message
		//Welcome back Darkcha0s, you have connected under the IP: blah. In local multiplayer it will be loopback.
		ply:SetTeam( 3 ) //Set it to this team, look in shared.lua for this one.
		// He should recieve the following weapons
		ply:Give( "weapon_crowbar" )
		ply:Give( "weapon_pistol" )
		ply:Give( "weapon_smg1" )
		ply:Give( "weapon_frag" )
		ply:Give( "weapon_physcannon" )
		ply:Give( "weapon_crossbow" )
		ply:Give( "weapon_shotgun" )
		ply:Give( "weapon_357" )
		ply:Give( "weapon_rpg" )
		ply:Give( "weapon_ar2" )
		ply:Give( "gmod_tool" )
	    ply:Give( "gmod_camera" )
	    ply:Give( "weapon_physgun" )
	end //end this if
	//For other characters, use elseif for example
	// elseif (ply:SteamID() == "STEAM 02984529" ) then 
	//ply:SetTeam( 2 ) 
	//etc. etc.
end //end the function
 


That's it, I hope I helped, I'll make more help soon.

Quick Start Gamemode .zip A .zip file containing everything from this tutorial, plus a ReadMe

Personal tools
Namespaces
Variants
Actions
Navigation
Lua Scripting
Functions
Hooks
Toolbox