It is a GSC script preprocessor for modders, for every Call of Duty which are using GSCs.

Posted by iCore on Nov 25th, 2013
Intermediate Server Side Coding.

The program can be downloaded here.

This tool lets you use some language elements, which are missing from GSC. For this, you have to work in a source folder, and the program will transform the code to proper GSC in another directory. It's also very good for compressing your scripts as much as possible.


[+] extern blocks
[+] -noforeach parameter
[×] print_r is writing in the console too

[+] Enum type
[+] Setting multiple variables
[×] References are loaded from imported files
[×] Faster file reading method
[-] Many fixes and corrigations

 [+] 'Start index' and 'size' parameter
 [+] Current index can be named
 [+] Can now be used with the 'as' keyword too, not only 'in'.
 [+] -zeroarray parameter
 [×] Enhanced in-game performance
 [-] Can be used without curly brackets

[+] do-while loop
[+] print_r function to print an array for debugging
[×] In debug mode, unneeded whitespaces will be removed
[-] Inline functions are not surrounded by curly brackets anymore
[-] Folder names in namespaces are not processed anymore as tokens

[+] Preprocessor directives
[+] Importing
[+] Inline functions
[+] Apostrophe strings
[+] Foreach
[+] Filled array and map definitions
[+] Default parameters
[-] Handling more extreme conditions

[-] Reference variables are now detected better

[+] Release

Setting up

Installing it is really simple. Just place preGSC.exe in mod's directory on Windows, and preGSC.out if you are using Linux. Make a source folder, and copy in that the scripts you are working with. After starting the program, it will convert all the scripts from source into the the maps folder (these names can be changed with attributes). With a shortcut (or a batch file, like makeMod.bat) you can pass some important attributes:

-d: It will turn debug mode on. Without debug mode, your scripts will be compressed totally to create a small file size and make it less readable for others. When turned on, it will keep the line breaks in your code, so if you are getting a script error, you will know the line where the error happened. It is suggested to leave it turned on while developing, and remove this parameter when you are ready and sure, that no more script errors will happen. Default: false

-nopause: It will disable pausing the program after a successful compile. Default: false

-infold: It sets the folder, where the script will be readed from. Default: source

-outfold: It is the output folder with the proper GSC syntax. Default: maps

-zeroarray: It is only used for foreach loop, description under. Default: false

-noforeach: It will totally disable processing foreach loops. Needed for games, which are supporting it as default, like MW2. Default: false

An example: E:\Call of Duty 4 - Modern Warfare\mods\test\preGSC.exe -d -infold scripts

New language elements

Conditional operator

Now you are free to use short if statements, just like in C++ (and many other languages):
condition ? value_if_true : value_if_false

Unlike in other languages, here you are enabled to leave the else part. This way, it will be undefined as default.

An example:

cpp code:
speed = level.wind == 2 ? 300 : 150;

So if level.wind is 2, then speed will be 300, otherwise 150.


Note: In the source code you can see an '& amp;' part. It is meant to be an '&' character, but the code plug-in on ModDB sadly encodes it.

Reference constants are aliases for variables/expressions. For example:

cpp code:
  &p = level.players;
  p[0] = self;
  p[1] = player;
  p[2] = attacker;

After running the program, every p constants will be replaced to level.players, making the code smaller and nicer. It is also perfect for defining global constants.

Default parameters
Default parameters can be set for each function. Expressions can also be used as default values (except checking isDefined on previous parameters with default value; those will always exist, so it is no use checking that). A parameter with default value can be followed by one without that. Example:

cpp code:
function_name(param1, param2 = 8, param3 = "iCore", param4 = getRankXP(self), p5)

Preprocessor directives

If you want to compile your scripts on different ways for any reason, like modding for different server versions, mod versions, debugging, etc, then these can help you much.
Supported: #define, #undef, #ifdef, #ifndef, #else, #endif. Usage is the same as in C++ and menus. These are not imported with #include, so you can add global definitions with the -globaldef parameter (which can be used multiple times), like: "-globaldef VER13 -globaldef LINUX". Also you can import them from a file, description for that later.

cpp code:
#ifndef RELEASE
  #define DEBUG
  iPrintLn(points + " points.");

Inline functions
Inline functions can help much on the performance, if you would have to pass/return big data structures (arrays, records). The point of it is, that while you can define it as a function, it will be inserted directly to every part of the code, from where you call it. It will save the time and memory, which is required to pass the parameters, and/or return the value.

cpp code:
inline removeLastElem(array)
  array[array.size - 1] = undefined;



You can load preprocessor definitions and inline functions in any GSC you want with the #import keyword. Usage:

cpp code:
#import mp/gametypes/_pregsc_ex.gsc

If your file contains 'pregsc', then it won't be processed as an individual GSC, only when imported.

You may already know this loop. It iterates through the elements of an array in a really comfortable way (single- and multi-line is supported too). As default, it uses getArrayKeys to query the elements of the array; but if your game does not support it (like Call of Duty 2), then you will have to use the -zeroarrays parameter. If set, it will handle every input array as zero-indexed arrays with ordered keys. You can use it even if your game supports getArrayKeys.

cpp code:
foreach (player in level.players)
  player.kills = 0;

It will set the kills of every player in level.players array. You can also use as keyword instead of in if you'd prefer that.

You also have opportunity to get the current index of iteration if you need:

cpp code:
foreach (player in i:level.players)
  player.clientid = i;

If you are using -zeroarrays, you can still loop through a non-zero based array (with ordered keys), since you can set the starting index this way:

cpp code:
foreach (e in weapons; 1)
  thread testWeap(e);

It will assume, that the weapons array is indexed from 1 to size, instead of from 0 to size - 1. Certainly you can pass there variables, and whole expressions too. By using this loop this way, it will not use getArrayKeys, nor without -zeroarrays parameter.
And if you are using -zeroarrays, while your game supports getArrayKeys, and sometimes you need to loop through an array with unordered keys, then you can still force the program to use getArrayKeys if you are placing @ instead of the starting index:

cpp code:
foreach (e in weapons; @)
  thread testWeap(e);

Also if you are looping through with getArrayKeys, you may not need only the iteration index, but also the array of the keys to determine the current key you are working with (you can also use it if -zeroarrays is not set) by defining the name of the key array after the @ character:

cpp code:
foreach (e in i:weapons; @keys)
  self setClientDvar("weapon" + keys[i], e);

The program will try to optimize as much as it can based on the known information, for example it optimizes differently based on the occurences of the array element in the loop body. However the array may have some properties, which cannot be decided by the program, but you can tell it. For example, if you know the size of the array, or you have already queried it in a variable because you needed it, then you should pass it as a second argument (you can ignore the first parameter if your array is starting with 0):

cpp code:
foreach (p in players; ; n)
  p loadInventory();

It will work with the n variable then instead of querying it again.

The other thing you can force the program to is, to ignore checking if the array is empty or not. So if you know, that your array is not empty, then place a + sign before the count of the array (or if you don't know the count, then just place the sign there). If your size parameter is not a variable but a numeric constant, then the program automatically assumes that it is not empty, so that way you don't need to use it.

cpp code:
foreach (p in players;;+)
  p.test = 0;

Maybe this tructure sounds horrible, but if you care much about performance, then you can get used to it. Let's see some examples, can you figure out what they are doing before checking their description under them?

cpp code:
foreach (e as i:p; 2; +c)
{ = i;

It will set the id parameter for every entity in the p array to the entity's index in the array. It also assumes, that the array is indexed from 2 to c + 1, the keys are ordered, and c is bigger than zero.

cpp code:
foreach (p as level.clans[clanId];@;+)
{ = 0;

It will set the id parameter for every entity in the level.clans[clanId] array to 0. It will get the arrays of the keys, and it also assumes, that the array is not empty.

cpp code:
foreach (p as j:wars;@k)
{ = k[j];

It will set the id parameter for every entity in the wars array to the entity's index in the array. It will get the arrays of the keys, but it will also check if the array is empty or not, since it knows nothing about the size.


It can be used the same way as in C-based languages (certainly with single-line and multi-line support too):

cpp code:
  level waittill("catch");
while (level.catches > 10);

Filled array definition
Now you can define arrays with starting values with the makearray function. Syntax:

cpp code:
arr makearray("Viking", "iCore", "BraXi", "Elzibob");

You can also define associative arrays (knows as maps in C++) with makemap.

cpp code:
arr makemap("name0" : "BraXi", "name1" : "Viking", "name2" : "Elzibob", "name3" : "iCore");


Now you can use enum types based on C++. Indexing starts from zero.

cpp code:


It is mostly made for Ninja's 1.7a serverfile. With this, you can separate GSC and GSX functions without making more files with different extensions (in the background they are created by the program), since the new serverfile prefers loading gsx file rather than gsc if it exists. After the extern keyword, put the file extension:

cpp code:
extern gsx
    exec("say Hello");

extern gsc
    self sayAll("Hello");

  self seyHello();

After running the code, sayHello() will work differently on 1.7 and 1.7a. Certainly if you need, you can use any file types, not only gsc and gsx.

Setting multiple variables
You can make your code shorter by setting the same value for more variables this way:

cpp code:
x, y, z = 0;

As a result, it'll be the same if you write this:

cpp code:
x = 0;
y = 0;
z = 0;

Apostrophe string definitions
Strings now can be defined with apostrophe characters too, like:

cpp code:
teststring = 'It is a string';

Printing an array for debugging
It is only working in games, which support getArrayKeys!
With the print_r function (known from PHP) you can print out the contents of an array, including the keys. It can be very helpful for debugging.

If you have any ideas, what can make GSC more comfortable, contact me.
Also if you find any bug in the program, please don't forget to report.

Post comment Comments
NNJ Jun 8 2014, 2:29pm says:


+1 vote     reply to comment
Post a Comment
click to sign in

You are not logged in, your comment will be anonymous unless you join the community today (totally free - or sign in with your social account on the right) which we encourage all contributors to do.

2000 characters limit; HTML formatting and smileys are not supported - text only

Report Abuse
Report article
Related Groups
SharpKode Developer & Publisher with 2 members