Call of Duty 4: Introduction: Difference between revisions

From COD Modding & Mapping Wiki
Jump to navigation Jump to search
No edit summary
(Lots of changes.)
Line 23: Line 23:
This section will include serveral things you need to know before you start scripting.
This section will include serveral things you need to know before you start scripting.


[[Image:Nutshell.png]] All scripts are contained within simple text files that contain no formatting, so programs such as Word are not to be used. The file format used for scripts within the Call of Duty series is 'GSC' (.gsc). It is recommended you use a simple but effective editor for programming, such programs include Crimson Editor, Programmers Notepad and Editplus.
[[Image:Nutshell.png]] All scripts are contained within simple text files that contain no formatting, so programs such as Word are not to be used. The file format used for scripts within the Call of Duty series is 'GSC' (.gsc). It is recommended you use a simple but effective editor for programming, such programs include [http://www.crimsoneditor.com/ Crimson Editor], [http://http://www.pnotepad.org/ Programmers Notepad] and [http://www.editplus.com/ Editplus].


A few things you need to know before reading any further are a few common words used within scripting.
A few things you need to know before reading any further are a few common words used within scripting.


Variables: variables are data storage locations which are assigned a name. For example...
'''Variables:''' variables are data storage locations which are assigned a name. For example...


  intVar = 1;
  integerthing = 1; //by the way, comments like this can be made using //, and are ignored by the game.
  floatVar = 0.5;
  floatthing = 0.5;  
  strVar = "Text";
  stringthing = "Text and symbols 1234567890";
  boolVar = true;
  booleanthing = true; //another thing, almost every line must have a ; at the end or the script won't work. More on that later.


The variables are declared on the left, and assigned a piece of data such as an integer (whole number), float (a number containing a decimal), string (text) or a boolean (true/false).
The variables are declared on the left, and assigned a value such as an integer (whole number), a float (a number containing a decimal), a string (text and symbols) or a boolean (true/false).


Entity: this is something that is used in maps which can be called in the script. Entities include players, guns, objectives, script_models, etc.
'''Entities:''' These are objects that are used in maps, and can be referenced in the script. Entities include players, dropped guns, objectives, script_models, etc.


They can be called using their relative targetname or classname which is defined in the map.
They can be referenced using their their targetname or classname that has been set within the map.


Functions: an action or procedure that can be called or threaded and can return a value. For example...
'''Functions:''' an action or procedure that can be called or threaded and can return a value. For example...


  funcMove()
  funcMove()
Line 47: Line 47:
  }
  }


The function in the above code is called "funcMove", when called, it will perform the actions inside the brackets.
The main function in the above code is '''funcMove()''', and it will perform the actions inside the curly braces when it runs. There is also another function, '''moveY''', which is a built-in function inside COD4, and moves an entity on the Y axis.


Arguement: these are required pieces of data that needs to be sent when requested from functions.
'''Arguements:''' These are key piece of information that are passed along to functions, and can be any type of object (entity, string, boolean etc). The function that was passed the arguments can then reference them.


For example, if a function is shown as
For example, if a function is shown as
Line 57: Line 57:
The function is asking for two arguements to be sent to the function. An example of this in use...
The function is asking for two arguements to be sent to the function. An example of this in use...


someotherstuff()
  {
  {
ent function(320, 5);
  ent function(320, 5);
  thing function(320, 5);
  }
  }


  function(dis, time)
  function(distance, time)
  {
  {
ent moveZ(dis, time);
  ent moveZ(distance, time);
  }
  }


As you can see, 'dis' is called and is given the value of 320, this can then be used as a variable called 'dis', ditto for time.
As you can see, function() is called on both 'ent' and 'thing', and the two arguments '320' and '5' are passed to the new function as 'distance' and 'time'. Then moveZ is called on the entities.


Calling/Threading: these are used with functions. A function can be called or they can be threaded.
'''Calling/Threading:''' these are used with functions. Functions can be threaded or called sequentially.


If a function is threaded, then the function is performed while the script continues, whereas if a function is called, the script will wait until the function is completed before it continues. Examples...
If a function is threaded, then that function is performed while the script continues, whereas if a function is called sequentially, the script waits until the function is completed before it continues. Examples...


  function(); // This is how to call a function
  function(); //the script will stop at this line and carry out function() before going down to...
  thread function(); // This is how to thread a function[/code]
  thread function(); //this will start function() and carry on to execute 'ent moveZ'
ent moveZ(350, 5);


'''Self:''' If you call a function on an entity e.g 'unnamedent thread dostuff()', then within the function dostuff(), you can refer to unnamedent as 'self'.


Self: this is used inside functions when a function is called on an entity. Self is used instead of an entity.
For example...
 
For example... (You will see in this example that in the function, called function(), self is equal to 'ent' which was decalred in a different function)


something()
  {
  {
   ent = getent("ent","targetname");
   ent = getent("ent","targetname");
Line 92: Line 95:
== [[Using Variables]] ==
== [[Using Variables]] ==


[[Image:Nutshell.png]] Variables can be used in several ways, but in all cases they are used to store some data for the duration of the round. Variables come in different style, integer, floats, strings and booleans, there are also several different ways variables can be stored.
[[Image:Nutshell.png]] Variables can be used in several ways, but in all cases they are used to store some data for the duration of the game. Variables come in different forms: integers, floats, entities, strings, arrays and booleans, there are also several different ways variables can be stored.


A simple variable is simply declared using
A simple variable is simply declared using


  <variable> = <data>;
  variable = data;


This variable can be used in the current function and any function that it is called to (using arguements, explained in section 1)
This variable can be used in the current function and any function that passes it as an argument, or is called on it (so it'd be used as 'self').


Variables can be global (which can be used in all threads without needing to be called) by using the
Variables can be global (which can be used in all threads without needing to be called) by using the


  level.<variable> = <data>
  level.variable = data;


or they can be assigned to entities individually
or they can be assigned to entities individually


  <entity>.<variable> = <data>
  entity.variable = data;
 
for things like player.health (integer, already built-in, but can be modified) and level.teamBased (boolean).


== Maths & Operators ==
== Maths & Operators ==


[[Image:Nutshell.png]] Maths is used throughout scripting to get several results, be it distance from two objects or simply to calculate a simple equation.
[[Image:Nutshell.png]] Maths is used throughout scripting to get many different values, be it the distance between two objects or to calculate an equation.


For example, a variable can be given data from an equation.
For example, a variable can be given data from an equation.


  <variable> = 5 + 1;
  variable = 5 + 1;


The above example is pretty pointless, as you could just calculate it yourself and use the answer i.e.
Although the above example is pretty pointless, as it adds one constant to another to make a constant, and you can just calculate it yourself and use the answer i.e.


  <variable> = 6;
  variable = 6;


But variables can be calculated using other variables, for example...
But variables can be calculated using other variables, for example...


  <varAnswer> = <var1> + <var2>;
  varAnswer = var1 + var2;


varAnswer will be equal to the value of var1 plus the value of var2.
varAnswer will be equal to the value of var1 plus the value of var2.
Line 144: Line 149:
Example of these in use...
Example of these in use...


  var++; // This is the same as var + 1
  var++; //Set var to var + 1
  var--; // This the same as var - 1
  var--; //Set var to var - 1
  var+=int; // This is the same as var + int (where int is a number)
  var += int; //Set var to var + int
  var-=int; // This is the same as var - int (where int is a number)
  var -= int; //Set var to var - int


== [[IFs, Loops & Logic]] ==
== [[IFs, Loops & Logic]] ==


[[Image:Nutshell.png]] This section is to go into a little more detail of how to use statements such as If and different loops.
[[Image:Nutshell.png]] This section will go into a little more detail of how to use 'if' statements and loops.


An 'If' statement is used to compare data and decide what is done after the data is compared.
An 'if' statement is used to verify whether some data satisfies certain conditions, and then to execute code depending on the outcome.


To go into detail in this section, It is required you know of 'Logic' and the operators used to compare data.
To understand this section, you must first know the operators used to compare data:


So...
<pre>
<pre>
== :: Equal To
== :: Equal To
!= :: Not Equal To
!= :: Not Equal To
!  :: Negation (Not)
!  :: Negation (Not equal to)
<  :: Less than
<  :: Less than
>  :: Greater than
>  :: Greater than
Line 169: Line 173:
|| :: Or
|| :: Or
</pre>
</pre>
Ok, now we have some operators, lets get started on the 'If' statement.


An 'If' statement, requires a minimum of one arguement and usually one operator.
Ok, now that we have some operators, lets get started on the statement.


Here are some examples...
An 'if' statement, requires a minimum of one arguement and usually one operator.


If(variable) // If variable is true
Here are some examples...notice the lack of semicolons at the end of the statements.
If(!variable) // If variable is not true
If(variable1 == variable2) // If variable1 is equal to variable2
If(variable1 != variable2) // If variable1 is not equal to variable2
If(integer1 < integer2) // If integer1 is less than integer2
If(integer1 > integer2) // If integer1 is greater than integer2
If(integer1 <= integer2) // If integer1 is less than or equal to integer2
If(integer1 >= integer2) // If integer1 is greater or equal to integer2
If((var1 == var2) && (var3 != var4)) // If var1 is equal to var2 AND var3 is not equal to var4
If((int1 > int2) || (var1 == var2)) // If int1 is greater than int2 OR var1 is equal to var2


To use an If statement to determine the movement of the script, you need to use the arguements to move the script in certain directions...
if(variable) //If variable is true
if(!variable) //If variable is not true
if(variable1 == variable2) //If variable1 is equal to variable2
if(variable1 != variable2) //If variable1 is not equal to variable2
if(integer1 < integer2) //If integer1 is less than integer2
if(integer1 > integer2) //If integer1 is greater than integer2
if(integer1 <= integer2) //If integer1 is less than or equal to integer2
if(integer1 >= integer2) //If integer1 is greater or equal to integer2
if((var1 == var2) && (var3 != var4)) //If var1 is equal to var2 AND var3 is not equal to var4
if((int1 > int2) || (var1 == var2)) //If int1 is greater than int2 OR var1 is equal to var2


  If(var1 == var2)
To use an if statement to determine the movement of the script, you need to use the arguements to move the script in certain directions...
 
  if(var1 == var2)
  {
  {
   // If statement is true, do this code
   //if var1 equals var2, do this code
  //everything inside these curly braces
  }
  }
  // more code here
  //then do this code regardless of the result


If the statement above is true, the code inside the curly brackets is processed, if it is not true, the code inside the brackets are skipped.
If the statement above is true, the code inside the curly brackets is processed, if it is not true, the code inside the brackets are skipped.
Line 198: Line 205:
Whether or not the statement is true, the code outside of the brackets is going to be processed. If this is not what you want, you need to use "Else" after the statement, for example...
Whether or not the statement is true, the code outside of the brackets is going to be processed. If this is not what you want, you need to use "Else" after the statement, for example...


  If(var1 == var2)
  if(var1 == var2)
  {
  {
   // If true
   //if it's true then do this
  }
  }
  Else
  else
  {
  {
   // If False
   //if it's false then do this
  }
  }


You can also use an "Else If" in the statement. This is used in a scenario where you want to check multiple comparisons.
You can also use an "else if" in the statement. This is used in a scenario where you want to check multiple comparisons.


  if(var1 == var2)
  if(var1 == var2)
  {
  {
   // If above arguement is true
   //if above arguement is true
  }
  }
  Else if(var1 == var3)
  else if(!var1 && var3)
  {
  {
   // If first arguement is false, but second is true.
   //if var1 is false but var3 is true
  }
  }
  Else
  else
  {
  {
   // If all arguements are false
   //if all other if statements were false
  }
  }


Thats the basics of If's, so let move to Loops.
Thats the basics of if's, so let move on to loops.


Loops come in different forms...
Loops come in different forms...
Line 229: Line 236:
'''For''' :: A for loop is a loop that loops a set amount of times
'''For''' :: A for loop is a loop that loops a set amount of times


To use a while loop, an arguement is needed "while(arguement);"
To use a while loop, a condition/some conditions must be stated: "while(conditions)"
Often, this loop is used for infinite loops. An infinite loop is a loop that loops forever. This is done using the arguement of 1 or true (1 is the integer of true)
Often, this loop is used for infinite loops, which last forever unless specifically stopped. This is done using the arguement of 1 or true (1 is the integer of true)


  while(1)
  while(1)
  while(true)
  while(true)


A while loop can also be used as a normal loop that loops while the arguement is true, when the arguement becomes false the loop exits automatically.
A while loop can also be used as a normal loop that loops while the arguement is true, when the arguement becomes false the loop exits automatically (or rather, doesn't begin executing the commands in the loop again but just finishes the loop in progress).


  int = 0;
  int = 0;
Line 249: Line 256:
The same applies for FOR loops.
The same applies for FOR loops.


An FOR loop requires 3 arguements.
A FOR loop requires 3 arguements.


for(declare;while;do)
for(declare; while; do)


Declare is the section which declares a variable for the loop to use.  
'''Declare''' is the section which declares a variable for the loop to use.  


While is what determines when the loop breaks
'''While''' is what determines when the loop breaks


Do is what the loop should do after each loop.
'''Do''' is what the loop should do after each loop.


A common FOR loop looks like this...
A common FOR loop looks like this...


  for(i=0;i<int;i++)
  for(i = 0; i < int; i++)


The above code is read, "'i' is equal to 0, while 'i' is less than 'int', add 1 to i.
The above code means: (i is 0, while i is smaller than int, add one to i).
Lets use the code, and replace int...


  for(i=0;i<10;i++)
Let's replace int with an actual number:
 
  for(i = 0; i < 10; i++)
  {
  {
wait 1;
  wait 1;
  thread function();
  }
  }


Line 274: Line 283:


- 'i' = 0
- 'i' = 0
- loop check "while" (if i is less than 10, continue)
- while i is less than 10, continue the loop
- perform code (wait 1;)
- perform code (wait 1; and function())
- increment 'i' (i++)
- increment 'i' (i++)
- 'i' = 1
- etc.


The FOR loop can also be used as an "infinite loop" using the "forever loop"
The FOR loop can also be used as an "infinite loop" using the "forever loop"
Line 284: Line 291:
  for(;;)
  for(;;)


The above will simply keep repeating the code until manual stopped.
The above will simply keep repeating the code until manually terminated.
 
The problem with infinite loops is they give an error if you do not allow the loop to take a breath.


Infinite loops require a wait statement. If you get an "Infinite Loop" error, this is the reason.
The problem with infinite loops is that they will give you an error if you don't allow them to pause at any point - so all infinite loops require a wait statement somewhere in the executed code.


That is about the loops, but to finish off, we need to know how to manually exit these loops. A common way to exit an infinite loop is to use an IF statement to determine when to 'break' (break is the keyword used to exit a loop) here is an example of an IF statement exiting an infinite loop...
To finish off, we need to know how to manually exit these loops. A common way to exit an infinite loop is to use an IF statement to determine when to 'break' (break is the keyword used to exit a loop) - here is an example of an IF statement breaking an infinite loop...


  for(;;)
  for(;;)
Line 296: Line 301:
   wait 1;
   wait 1;
   if(var1 == var2)
   if(var1 == var2)
    {
  {
      break;
    break;
    }
  }
  }
  }


The above sequence simply goes...
The above sequence simply goes...
- Wait 1
 
- wait 1 second
- check if statement...
- check if statement...
+ if var1 is equal to var2, exit loop
- if var1 is equal to var2, break out of the loop
+ else continue
- else continue the loop
- loop


== [[Creating Functions]] ==
== [[Creating Functions]] ==


[[Image:Nutshell.png]] A custom function is a good way to use repeat sections of code more efficiently. For example, if you often use
[[Image:Nutshell.png]] A custom function is a good way to use repeat sections of code more efficiently. For example, if you often use the same sequence of code, you can template them into a custom function. Imagine this is your code...
the same sequence of code, you can template them into a custom function. Imagine this is your code...


{
  wait 1;
  wait 1;
  brush1 moveZ(320, 5);
  brush1 moveZ(320, 5);
Line 319: Line 324:
  brush2 moveZ(540, 3);
  brush2 moveZ(540, 3);
  brush2 waittill("movedone");
  brush2 waittill("movedone");
}


This can be simplified using a custom function, lets call this function "_moveEnt" (it is common practice to use an underscore as the first character of a function)
This can be simplified using a custom function, lets call this function "_moveEnt" (it is common practice to use an underscore as the first character of a function)
Line 340: Line 346:
  }
  }


As the above code shows, the custom function can simply be called using the required arguements, each time it is called, the details are changed in the custom function and are processed.
As the above code shows, the custom function can simply be called using the required arguements, which are passed along and used in the new function.


Once they are finished, it goes back to the main function.
Once the custom function has finished, the script returns to the original location from where it was called.


Functions can also return values, for example performaing mathmatical equations.
Functions can also return values to the original script, or even entities.
A new function to get 3D area...
 
A simple function to calculate volume from the width, height and depth:


  {
  {
Line 351: Line 358:
  }
  }


  _areaEquation(a, b, c)
  _areaEquation(x, y, z)
  {
  {
   answer = (a * b) * c;
   answer = x * y * z;
   return answer;
   return answer;
  }
  }
Line 360: Line 367:
This declares a new variable (area). The variable area, is the answer that is returned by the function.
This declares a new variable (area). The variable area, is the answer that is returned by the function.


== [[Arrays]] ==
The two lines:


[[Image:Nutshell.png]] Arrays are "multivariables". You can store several pieces of data within a single array. This can be integers, strings or pieces of data such as targetnames and etc.
answer = x * y * z;
return answer;


Arrays are the answwer to having to use multiple variables or in mapping, you can use a single targetname.
could be replace by


Arrays are the key to more efficient scripts and maps. If your map contains lots of entities which do the exact same thing (such as moving platforms) then you should be using an array to manipulate them.
  return x * y * z;


To create an array we simply type...
for the same effect.


arrayName = [];


Now we have an array, we need to add to this array, this would be a pretty advanced process if the IW developers had not built a function for us. The function can be accessed using...
== [[Arrays]] ==


maps\mp\_utility::add_to_array(array, ent);[/code]
[[Image:Nutshell.png]] Arrays are objects that store several variables. These can be integers, strings, entities or even other arrays.


So, for example, we have an array called "arrayName" and what we want to add is a string in a variable named "arrayString", put that into the above code...
Arrays are extremely helpful when it comes to doing the same thing to several different objects, such as moving a few platforms by a certain amount in a map, or storing lots of related variables.


maps\mp\_utility::add_to_array(arrayName, arrayString);
To create an array we simply type...


Now, a couple of things to remember about arrays is their size.
arrayName = [];
Whenever you see, <ent>.size the .size does not mean dimension, but "how many". So if an array contains 1 piece of data, the array.size is 1.
Another thing is calling the array. A piece of data is called from an array using the array number...


So, if we go back to the example, we have just put arrayString inside arrayName, so our arrayName.size = 1. To get that information back we use
Now, to add an object/variable to this array, we can simply use:


  arrayName[0]
  array(array.size) = "a string variable";


This is where it gets a little confusing. Your array size is always 1 bigger than you array, this is because your array starts at 0.
Whenever you see array.size, the .size does not mean it's dimensions, but the amount of items in the array. So if an array contains 1 piece of data, the array.size is 1. To retrieve an items from an array, you can use array[0] for the first object/var stored in it, and then array[1] and so on for successive items.
If you had 10 pieces of data in the array, the size would be ten but you would only be able to call [0]-[9].


A common use for the array is to thread a function to all of the players on the server. This can be done using an array with a for loop.
Going back to the example above, we could retrieve the data by using array[0]. The first item in an array is listed as 0, the second as 1, and so on. This means that by using array(array.size) = "blah";, we can add new items to it because of the offset of 1.
So, first off we must get our array, and instead of using the above method of defining an array and adding custom data, we use a builtin command.


players = getEntArray("player", "classname");


So, our array has been defined as "players" or more accurately "players[]"
A common use for an array is to call a function on all of the players in the game. This can be done by using an array with a FOR loop.
Inside "players[]" is every player on the server, and now all we need to do is use the array to thread a function to each player.
To start with we must get our array of players, and instead of using the above method of defining an array and adding custom data, we can use a builtin function.
So, here we have a for loop to do such a thing.


players = getEntArray("player", "classname");


for(i=0;i<players.size;i++)
So, our array has been defined as "players", or more accurately, "players[]".


Thats our loop, 'i=0' (do not change this number, it is important). While 'i' is LESS than 'players.size' (remember, the size is always 1 bigger than the final number in the array), 'i++'.
Inside "players[]" is every player on the server, and now all we need to do is use the array to thread a function to each player.
So, here we have a for loop to do such a thing:


for(i = 0; i < players.size; i++)
  {
  {
   players[i] thread function();
   players[i] thread function();
  }
  }


And that above simply threads the function to each person in the array. Remember, 'i' is a variable not a letter, so 'i' is substitued with the number of the loop.
That's our loop to go through every player and call function(); on them.
The first loop, 'i' equals 0, so
 
Remember, 'i' is a variable not a letter, so 'i' is substitued with the number of the loop.
In the first loop, 'i' equals 0, so:


  players[0] thread function();
  players[0] thread function();


The second loop, 'i' equals 1 and etc.
is executed.
If the amount of players on the server is 10 then loop will loop while 'i' is less than the size of the array (10). This means the 'i' will equal 0,1,2...,9.


Arrays are a complicated part of scripting, but once you have them understood, they are one of the most useful things.
Arrays are a complicated part of scripting, but once you have them understood, they are one of the most useful things in the game.


== [[Switch]] ==
== [[Switch]] ==


[[Image:Nutshell.png]] Switch is often used when there are multiple limited outcomes for a single variable.
[[Image:Nutshell.png]] Switch is often used instead of multiple if statements, as it is more efficient and doesn't require you to type as much.
 
The Switch function can often be replaced by lots of "If" and "Else If" statements, but Switch is more efficient when the variable being checked has a limited amount of outcomes.


''How to use "Switch".''
''How to use "Switch".''
Line 435: Line 438:
  switch(response)
  switch(response)
  {
  {
  case "changeweapon":
  case "changeweapon":
   self closeMenu();
   self closeMenu();
Line 442: Line 446:
   else if(self.pers["team"] == "axis")
   else if(self.pers["team"] == "axis")
       self openMenu(game["menu_weapon_axis"]);
       self openMenu(game["menu_weapon_axis"]);
  break;   
break;   
 


  case "changeteam":
  case "changeteam":
Line 448: Line 453:
   self closeInGameMenu();
   self closeInGameMenu();
   self openMenu(game["menu_team"]);
   self openMenu(game["menu_team"]);
  break;
break;
 


  case "muteplayer":
  case "muteplayer":
Line 455: Line 461:
   self openMenu(game["menu_muteplayer"]);
   self openMenu(game["menu_muteplayer"]);
   break;
   break;


  case "callvote":
  case "callvote":
Line 462: Line 469:
   break;
   break;
    
    
  //default:
 
   // Add default here
  default:
   // break;    
   //add default action here
   break;
  }
  }


The first part of the code is where the variable is defined. The game waits until a menu has been activated. The variables recieved are "menu" (the name of the menu activated) and "response" (what option was chosen from the menu). "Response" is the key variable for the 'Switch'.
The first part of the code is where the variable is defined. The game waits until a menu has been activated. The variables recieved are "menu" (the name of the menu activated) and "response" (what option was chosen from the menu). "Response" is the key variable for the 'Switch'.


After the variables have been defined, the Switch function is called. It then checks every "Case" (case is the term used for the possible outcomes of the variable) to find a match, if no match is found, the "Default" case is used. (If you do not have a Default case, the script will continue passed the 'Switch' function).
After the variables have been defined, the Switch function is called. It then checks every "Case" (case is the term used for the possible outcomes of the variable) to find a match, if no match is found, the "Default" case is used. (if you do not have a default case, the script will crash - you can just add an empty one.)


If a match is found, then the function will do ALL the events from that point onwards, which is why you MUST add "break;" at the end of every case, if the break is not existent, then all other case functions will run also.
If a match is found, then the function will do ALL the events from that point onwards, which is why you MUST add "break;" at the end of every case, if the break is not existent, then all other case functions will run also.
Line 480: Line 488:


Once the match is found, everything after the case will happen:
Once the match is found, everything after the case will happen:
* self closeMenu(); (Current menu closes)
* self closeMenu(); //current menu closes
* self closeInGameMenu(); (Close any other ingame menus)
* self closeInGameMenu(); //close any other ingame menus
* self openMenu(game["menu_team"]); (Will open the team menu).
* self openMenu(game["menu_team"]); //will open the team menu
* break; (The rest of the switch statement is ended and the code continues.
* break; //the rest of the switch statement is ended and the code continues
 
You can also make the script perform the same actions in multiple cases. For example:
 
self waittill("menuresponse", menu, response);
 
switch(response)
{
 
case "changeweapon":
case "changeteam":
case "muteplayer":
case "callvote":
  function();
  break;
 
 
default:
  //add default action here
  break;
}
 
This means that is the response variable is: 'changeweapon', 'changeteam', 'muteplayer' or 'callvote', function(); will be called.
 


== [[Notify / Endon / Waittill]] ==
== [[Notify / Endon / Waittill]] ==


[[Image:Nutshell.png]] These 3 functions can be used to do many things, they are often used to "end" a script/function from running, they can be used to stop a script running until another part of the code is ready for it to continue and it can be used in simple debugging (although, not the only way).
[[Image:Nutshell.png]] These 3 functions allow you to make a script wait for specific events and then trigger those events in different parts of the scripts.


The functions are often used mainly on a player or the level. I will provide an example of each.
This one ends the function it is inside when 'thread_restart' is triggered on 'level':


  level endon ("thread_restart");
  level endon ("thread_restart");


and from any gametype script.
and this triggers the 'killed_player' notification on 'self' (which is a player in this case):


  self notify("killed_player");
  self notify("killed_player");


If you use "player waittill" or "player endon", then using a "level notify" will not trigger any of the 2.
If you use 'player waittill("x")' or 'player endon("x")', then using a 'level notify("x")' will not trigger either of them - level is not the same entity as player, and all entities' triggers are independant.
 
To use the functions is very easy. First you decide on what you want the function to be called on.  


If the action is going to happen to a specific player, then use "player" (although, this will need to change depending on how the player is being called, i.e. self, other, user, etc), or if you want the function to work for the entire script, use level.
Using the functions is easy. Firstly, decide which entity you want to wait for the trigger on. This is a player most of the time, but if you want a global trigger then use 'level'.


Then you must decide which function to use. You need to choose, either "endon" or "waittill", they are both self explanatory, one will end when called, and the other will 'wait'.
Then you must decide which trigger to use. You can choose either "endon" or "waittill" - they are both self explanatory, one will end the function it is running in when triggered, and the other will 'wait' until the specified trigger.


----
----


Next you decide on a unique 'call' for the function. For exmaple...
Next you decide on a unique name for the trigger. For example...


  level endon("a_unique_call");
  level endon("a_unique_call");


Now. when you want the 'endon' function to happen, you will use the 'Notify' function...
And to activate this trigger, you use notify on the same entity (level):


  level notify("a_unique_call");
  level notify("a_unique_call");


Anything with the unique call will be activated, so, multiple 'endon' and 'waittill' functions can be placed around your script.
You can use as many waittill and endon functions as you want on an entity, in different functions. They will all be triggered by a notify.


Here is a quick example of it in use in multiple threads in the DM gametype...
Here is a quick example of it in use in multiple threads in the DM gametype...
Line 521: Line 550:
  spawnPlayer()
  spawnPlayer()
  {
  {
  self endon("disconnect");
   self notify("spawned");
   self notify("spawned");
  self notify("end_respawn");
    
    
   /*... Code Snipped ...*/
   /*... Code snipped ... this is another type of
  comment that can span multiple lines. */
    
    
  self notify("spawned_player");
  }
  }


  Callback_PlayerKilled(?, ?, ?, ?, ?, ?, ?, ?, ?)
  Callback_PlayerKilled(attacker, some other arguments)
  {
  {
   self endon("spawned");
   self endon("spawned"); //this makes callback_playerkilled() terminate when "spawned" is triggered in spawnplayer().
  self notify("killed_player");
 
  attacker notify("update_playerhud_score");
  }
  }


spawnSpectator(origin, angles)
== Random stuff ==
{
 
  self notify("spawned");
 
  self notify("end_respawn");
 
}
A few useful commands:
 
To print a large message on the screen:
 
'''iprintlnbold(stringMessage);'''
or to a specific player:
'''player iprintlnbold(stringMessage);'''
 
To print a small message on the bottom left of the screen:
 
'''iprintln(stringMessage);
same as iprintlnbold() to a specific player
 
 
To check whether a variable or entity exists:
 
'''if(isdefined(timetowait))'''
  '''wait (timetowait);'''
 
 
You can also use functions in if statements, by the returned value:


All the threads depend on those notifies being called.
if(checksomething())
Here is a quick easy demonstration...
  //code here


waiting_thread()
checksomething()
{
{
  level waittill("stop_waitting", user);
  if(var == "hi there!") //remember to use == in if statements to check equality, but var1 = var2 to set equality outside them.
  iprintln("This thread has stopped waitting, because " + user.name + " touched the trigger");
    return true;
}
  else
    return false;
}


trigger()
{
  trigger waittill("trigger", user);
  level notify("stop_waitting", user);
}


== Sources ==
== Sources ==


[[Image:Geographylogo.png]][http://www.codjumper.com/forums/viewtopic.php?t=4011&sid=ed58d3b3f5bfa32350d4670d35c9f781 From CoDJumper.com]
[[Image:Geographylogo.png]][http://www.codjumper.com/forums/viewtopic.php?t=4011&sid=ed58d3b3f5bfa32350d4670d35c9f781 From CoDJumper.com]

Revision as of 02:28, 24 October 2008

Here is a very good tutorial on COD coding that my mate Danny Redford (hence - Drofder, as its Redford
backwards :))
wrote back in 2006, which is a succint introduction to a very complex thing. Tally;

By Drofder2004

Ok, this is my own guide for scripting, it is incomplete and lacks a lot of formatting (I will try and get round to that soon). It was written in 2.5 hours and contains a lot of basic and slightly advanced guides on several base topics. Some areas contain more detail than others depending on relevance and difficulty.

When I get more time, I will add to this guide. Once I have pretty much finished the majority of the guide I will provide several new scripts using several advanced functions.

This guide should be used as a small starting guide for people new to scripting, and reference for those who know some scripting. This will provide an insight into how script can improve the fun of maps, and hopefully will help answer questions for those who are stuck.

If you find any problems (be it wrong syntax, spelling or etc) then post. If you want to request/criticise/compliments or whatever, again post.

Enjoy.

Getting Started

This section will include serveral things you need to know before you start scripting.

All scripts are contained within simple text files that contain no formatting, so programs such as Word are not to be used. The file format used for scripts within the Call of Duty series is 'GSC' (.gsc). It is recommended you use a simple but effective editor for programming, such programs include Crimson Editor, Programmers Notepad and Editplus.

A few things you need to know before reading any further are a few common words used within scripting.

Variables: variables are data storage locations which are assigned a name. For example...

integerthing = 1; //by the way, comments like this can be made using //, and are ignored by the game.
floatthing = 0.5; 
stringthing = "Text and symbols 1234567890";
booleanthing = true; //another thing, almost every line must have a ; at the end or the script won't work. More on that later.

The variables are declared on the left, and assigned a value such as an integer (whole number), a float (a number containing a decimal), a string (text and symbols) or a boolean (true/false).

Entities: These are objects that are used in maps, and can be referenced in the script. Entities include players, dropped guns, objectives, script_models, etc.

They can be referenced using their their targetname or classname that has been set within the map.

Functions: an action or procedure that can be called or threaded and can return a value. For example...

funcMove()
{
  self moveY(320, 3);
}

The main function in the above code is funcMove(), and it will perform the actions inside the curly braces when it runs. There is also another function, moveY, which is a built-in function inside COD4, and moves an entity on the Y axis.

Arguements: These are key piece of information that are passed along to functions, and can be any type of object (entity, string, boolean etc). The function that was passed the arguments can then reference them.

For example, if a function is shown as

function(arg1, arg2)

The function is asking for two arguements to be sent to the function. An example of this in use...

someotherstuff()
{
  ent function(320, 5);
  thing function(320, 5);
}
function(distance, time)
{
  ent moveZ(distance, time);
}

As you can see, function() is called on both 'ent' and 'thing', and the two arguments '320' and '5' are passed to the new function as 'distance' and 'time'. Then moveZ is called on the entities.

Calling/Threading: these are used with functions. Functions can be threaded or called sequentially.

If a function is threaded, then that function is performed while the script continues, whereas if a function is called sequentially, the script waits until the function is completed before it continues. Examples...

function(); //the script will stop at this line and carry out function() before going down to...
thread function(); //this will start function() and carry on to execute 'ent moveZ'
ent moveZ(350, 5);

Self: If you call a function on an entity e.g 'unnamedent thread dostuff()', then within the function dostuff(), you can refer to unnamedent as 'self'.

For example...

something()
{
 ent = getent("ent","targetname");
 ent function();
}
function()
{
 self moveZ(150, 5);
}

Using Variables

Variables can be used in several ways, but in all cases they are used to store some data for the duration of the game. Variables come in different forms: integers, floats, entities, strings, arrays and booleans, there are also several different ways variables can be stored.

A simple variable is simply declared using

variable = data;

This variable can be used in the current function and any function that passes it as an argument, or is called on it (so it'd be used as 'self').

Variables can be global (which can be used in all threads without needing to be called) by using the

level.variable = data;

or they can be assigned to entities individually

entity.variable = data;

for things like player.health (integer, already built-in, but can be modified) and level.teamBased (boolean).

Maths & Operators

Maths is used throughout scripting to get many different values, be it the distance between two objects or to calculate an equation.

For example, a variable can be given data from an equation.

variable = 5 + 1;

Although the above example is pretty pointless, as it adds one constant to another to make a constant, and you can just calculate it yourself and use the answer i.e.

variable = 6;

But variables can be calculated using other variables, for example...

varAnswer = var1 + var2;

varAnswer will be equal to the value of var1 plus the value of var2.

There are several operators that can be used in maths...

+ :: Addition
- :: Subtraction
* :: Multiplication
/ :: Division
% :: Modulus
= :: Equals

There are also some more little-known operators such as...

++ :: Increment (+1)
-- :: Decrement (-1)
+= :: Incrementation (requires number)
-= :: Decrementation (requires number)

Example of these in use...

var++; //Set var to var + 1
var--; //Set var to var - 1
var += int; //Set var to var + int
var -= int; //Set var to var - int

IFs, Loops & Logic

This section will go into a little more detail of how to use 'if' statements and loops.

An 'if' statement is used to verify whether some data satisfies certain conditions, and then to execute code depending on the outcome.

To understand this section, you must first know the operators used to compare data:

== :: Equal To
!= :: Not Equal To
!  :: Negation (Not equal to)
<  :: Less than
>  :: Greater than
<= :: Less or Equal to
>= :: Greater or Equal to
&& :: And
|| :: Or

Ok, now that we have some operators, lets get started on the statement.

An 'if' statement, requires a minimum of one arguement and usually one operator.

Here are some examples...notice the lack of semicolons at the end of the statements.

if(variable) //If variable is true
if(!variable) //If variable is not true
if(variable1 == variable2) //If variable1 is equal to variable2
if(variable1 != variable2) //If variable1 is not equal to variable2
if(integer1 < integer2) //If integer1 is less than integer2
if(integer1 > integer2) //If integer1 is greater than integer2
if(integer1 <= integer2) //If integer1 is less than or equal to integer2
if(integer1 >= integer2) //If integer1 is greater or equal to integer2
if((var1 == var2) && (var3 != var4)) //If var1 is equal to var2 AND var3 is not equal to var4
if((int1 > int2) || (var1 == var2)) //If int1 is greater than int2 OR var1 is equal to var2

To use an if statement to determine the movement of the script, you need to use the arguements to move the script in certain directions...

if(var1 == var2)
{
  //if var1 equals var2, do this code
  //everything inside these curly braces
}
//then do this code regardless of the result

If the statement above is true, the code inside the curly brackets is processed, if it is not true, the code inside the brackets are skipped.

Whether or not the statement is true, the code outside of the brackets is going to be processed. If this is not what you want, you need to use "Else" after the statement, for example...

if(var1 == var2)
{
  //if it's true then do this
}
else
{
  //if it's false then do this
}

You can also use an "else if" in the statement. This is used in a scenario where you want to check multiple comparisons.

if(var1 == var2)
{
  //if above arguement is true
}
else if(!var1 && var3)
{
  //if var1 is false but var3 is true
}
else
{
  //if all other if statements were false
}

Thats the basics of if's, so let move on to loops.

Loops come in different forms...

While :: A while loop is a loop that keeps looping WHILE the arguement is true. For :: A for loop is a loop that loops a set amount of times

To use a while loop, a condition/some conditions must be stated: "while(conditions)" Often, this loop is used for infinite loops, which last forever unless specifically stopped. This is done using the arguement of 1 or true (1 is the integer of true)

while(1)
while(true)

A while loop can also be used as a normal loop that loops while the arguement is true, when the arguement becomes false the loop exits automatically (or rather, doesn't begin executing the commands in the loop again but just finishes the loop in progress).

int = 0;
while(int < 10)
{
 wait 1;
 int++;
}

The above code will loop while 'int' is less than 10. The loop waits 1 second, and then the loop increments 'int'. Once 'int' is not less than 10, the loop breaks.

The same applies for FOR loops.

A FOR loop requires 3 arguements.

for(declare; while; do)

Declare is the section which declares a variable for the loop to use.

While is what determines when the loop breaks

Do is what the loop should do after each loop.

A common FOR loop looks like this...

for(i = 0; i < int; i++)

The above code means: (i is 0, while i is smaller than int, add one to i).

Let's replace int with an actual number:

for(i = 0; i < 10; i++)
{
 wait 1;
 thread function();
}

This is the sequence of events...

- 'i' = 0 - while i is less than 10, continue the loop - perform code (wait 1; and function()) - increment 'i' (i++)

The FOR loop can also be used as an "infinite loop" using the "forever loop"

for(;;)

The above will simply keep repeating the code until manually terminated.

The problem with infinite loops is that they will give you an error if you don't allow them to pause at any point - so all infinite loops require a wait statement somewhere in the executed code.

To finish off, we need to know how to manually exit these loops. A common way to exit an infinite loop is to use an IF statement to determine when to 'break' (break is the keyword used to exit a loop) - here is an example of an IF statement breaking an infinite loop...

for(;;)
{
  wait 1;
  if(var1 == var2)
  {
    break;
  }
}

The above sequence simply goes...

- wait 1 second - check if statement... - if var1 is equal to var2, break out of the loop - else continue the loop

Creating Functions

A custom function is a good way to use repeat sections of code more efficiently. For example, if you often use the same sequence of code, you can template them into a custom function. Imagine this is your code...

{

wait 1;
brush1 moveZ(320, 5);
brush1 waittill("movedone");
wait 1;
brush2 moveZ(540, 3);
brush2 waittill("movedone");

}

This can be simplified using a custom function, lets call this function "_moveEnt" (it is common practice to use an underscore as the first character of a function)

_moveEnt(ent, dist, time)

As the above shows, we are going to need 3 arguements, ent (entity), dist (distance) and time.

Now lets look at the full code with custom function in use...

{
  _moveEnt(brush1, 320, 5);
  _moveEnt(brush2, 540, 3);
}
_moveEnt(ent, dist, time)
{
  wait 1;
  ent moveZ(dist, time);
  ent waittill("movedone");
}

As the above code shows, the custom function can simply be called using the required arguements, which are passed along and used in the new function.

Once the custom function has finished, the script returns to the original location from where it was called.

Functions can also return values to the original script, or even entities.

A simple function to calculate volume from the width, height and depth:

{
  area = _areaEquation(2, 4, 6);
}
_areaEquation(x, y, z)
{
  answer = x * y * z;
  return answer;
}

Once the code calls the function '_areaEquation' the function works out the 'answer', 'answer' is the returned. This declares a new variable (area). The variable area, is the answer that is returned by the function.

The two lines:

answer = x * y * z;
return answer;

could be replace by

  return x * y * z;

for the same effect.


Arrays

Arrays are objects that store several variables. These can be integers, strings, entities or even other arrays.

Arrays are extremely helpful when it comes to doing the same thing to several different objects, such as moving a few platforms by a certain amount in a map, or storing lots of related variables.

To create an array we simply type...

arrayName = [];

Now, to add an object/variable to this array, we can simply use:

array(array.size) = "a string variable";

Whenever you see array.size, the .size does not mean it's dimensions, but the amount of items in the array. So if an array contains 1 piece of data, the array.size is 1. To retrieve an items from an array, you can use array[0] for the first object/var stored in it, and then array[1] and so on for successive items.

Going back to the example above, we could retrieve the data by using array[0]. The first item in an array is listed as 0, the second as 1, and so on. This means that by using array(array.size) = "blah";, we can add new items to it because of the offset of 1.


A common use for an array is to call a function on all of the players in the game. This can be done by using an array with a FOR loop. To start with we must get our array of players, and instead of using the above method of defining an array and adding custom data, we can use a builtin function.

players = getEntArray("player", "classname");

So, our array has been defined as "players", or more accurately, "players[]".

Inside "players[]" is every player on the server, and now all we need to do is use the array to thread a function to each player. So, here we have a for loop to do such a thing:

for(i = 0; i < players.size; i++)
{
  players[i] thread function();
}

That's our loop to go through every player and call function(); on them.

Remember, 'i' is a variable not a letter, so 'i' is substitued with the number of the loop. In the first loop, 'i' equals 0, so:

players[0] thread function();

is executed.

Arrays are a complicated part of scripting, but once you have them understood, they are one of the most useful things in the game.

Switch

Switch is often used instead of multiple if statements, as it is more efficient and doesn't require you to type as much.

How to use "Switch".

Switch can be quite hard to understand at first glance, but after using it, it will become easier.

Here is an example of how it is used. This is taken from the menu scripts, which handles the ingame menus, I have cut the code and also added the commented lines myself.

self waittill("menuresponse", menu, response);
switch(response)
{
case "changeweapon":
  self closeMenu();
  self closeInGameMenu();
  if(self.pers["team"] == "allies")
     self openMenu(game["menu_weapon_allies"]);
  else if(self.pers["team"] == "axis")
     self openMenu(game["menu_weapon_axis"]);
break;   


case "changeteam":
  self closeMenu();
  self closeInGameMenu();
  self openMenu(game["menu_team"]);
break;


case "muteplayer":
  self closeMenu();
  self closeInGameMenu();
  self openMenu(game["menu_muteplayer"]);
  break;


case "callvote":
  self closeMenu();
  self closeInGameMenu();
  self openMenu(game["menu_callvote"]);
  break;
  
default:
  //add default action here
  break;
}

The first part of the code is where the variable is defined. The game waits until a menu has been activated. The variables recieved are "menu" (the name of the menu activated) and "response" (what option was chosen from the menu). "Response" is the key variable for the 'Switch'.

After the variables have been defined, the Switch function is called. It then checks every "Case" (case is the term used for the possible outcomes of the variable) to find a match, if no match is found, the "Default" case is used. (if you do not have a default case, the script will crash - you can just add an empty one.)

If a match is found, then the function will do ALL the events from that point onwards, which is why you MUST add "break;" at the end of every case, if the break is not existent, then all other case functions will run also.

To use the above example, I shall input my own values to show how the example works...

When I open the menu ingame, I choose the option "changeteam". The code kicks in and the variable "response" becomes equal to "changeteam". The switch statement will now look at every case for a positive match.

Once the match is found, everything after the case will happen:

  • self closeMenu(); //current menu closes
  • self closeInGameMenu(); //close any other ingame menus
  • self openMenu(game["menu_team"]); //will open the team menu
  • break; //the rest of the switch statement is ended and the code continues

You can also make the script perform the same actions in multiple cases. For example:

self waittill("menuresponse", menu, response);
switch(response)
{
case "changeweapon":
case "changeteam":
case "muteplayer":
case "callvote":
  function();
  break;
  
default:
  //add default action here
  break;
}

This means that is the response variable is: 'changeweapon', 'changeteam', 'muteplayer' or 'callvote', function(); will be called.


Notify / Endon / Waittill

These 3 functions allow you to make a script wait for specific events and then trigger those events in different parts of the scripts.

This one ends the function it is inside when 'thread_restart' is triggered on 'level':

level endon ("thread_restart");

and this triggers the 'killed_player' notification on 'self' (which is a player in this case):

self notify("killed_player");

If you use 'player waittill("x")' or 'player endon("x")', then using a 'level notify("x")' will not trigger either of them - level is not the same entity as player, and all entities' triggers are independant.

Using the functions is easy. Firstly, decide which entity you want to wait for the trigger on. This is a player most of the time, but if you want a global trigger then use 'level'.

Then you must decide which trigger to use. You can choose either "endon" or "waittill" - they are both self explanatory, one will end the function it is running in when triggered, and the other will 'wait' until the specified trigger.


Next you decide on a unique name for the trigger. For example...

level endon("a_unique_call");

And to activate this trigger, you use notify on the same entity (level):

level notify("a_unique_call");

You can use as many waittill and endon functions as you want on an entity, in different functions. They will all be triggered by a notify.

Here is a quick example of it in use in multiple threads in the DM gametype...

spawnPlayer()
{
  self notify("spawned");
  
  /*... Code snipped ... this is another type of 
  comment that can span multiple lines. */
  
}
Callback_PlayerKilled(attacker, some other arguments)
{
  self endon("spawned"); //this makes callback_playerkilled() terminate when "spawned" is triggered in spawnplayer().
}

Random stuff

A few useful commands:

To print a large message on the screen:

iprintlnbold(stringMessage); or to a specific player: player iprintlnbold(stringMessage);

To print a small message on the bottom left of the screen:

iprintln(stringMessage); same as iprintlnbold() to a specific player


To check whether a variable or entity exists:

if(isdefined(timetowait))

 wait (timetowait);


You can also use functions in if statements, by the returned value:

if(checksomething())

 //code here

checksomething() {

 if(var == "hi there!") //remember to use == in if statements to check equality, but var1 = var2 to set equality outside them.
   return true;
 else
   return false;

}


Sources

From CoDJumper.com