Wiki
Clone wikiNuclearThroneTogether / Scripting / Language Features
The following are the differences and extensions of scripting language used, compared to GameMaker Language itself:
Script/function definitions
Script/function definition syntax matches the little-known multiscript/extension script file syntax in GameMaker.
That is, each script/function is to be preceded by a #define scriptName
header-line and will be considered to span until the next header or the end of file. For example,
#!cpp #define init test("Hello!"); #define test trace("Test: " + argument0);
Named arguments
While you can use the standard argument#
variables to access arguments, there is also a bit of syntax for naming them.
To use it, simply open parentheses after the #define
statement and list the arguments:
#define draw_text_bang(rx, ry, text) draw_text(rx, ry, text + "!");
#define draw_text_bang draw_text(argument0, argument1, argument2 + "!");
Macro definitions
As with GMS2, you can declare mod-wide macros by using #macro name value
syntax,
#macro version 1001 // ... trace(version); // equivalent to trace(1001)
Ternary operator
Ternary (inline if-then-else) operator is supported. This means that you can do, for example
#!as draw_set_color(instance_exists(Player) ? c_red : c_blue);
#!as if (instance_exists(Player)) { draw_set_color(c_red); } else draw_set_color(c_blue);
Array write
Array access behavior is "create-on-write", meaning that when you do
#!as var a; a[0] = 1; a[1] = 2;
#!as var a; if (!is_array(a)) a = array_create(0); a[@0] = 1; a[@1] = 2;
array_create
or array declaration syntax (see below) and use [@index]
array access syntax to indicate that you are sure that a variable is an array and there's no need to ensure that it is an array prior to writing.
Array declaration
JavaScript-like array declaration syntax is supported, meaning that you can do
#!as var a = [1, 2, 3];
#!as var a = array_create(3); a[@0] = 1; a[@1] = 2; a[@2] = 3;
Accessors
Unlike the regular GML (so far), accessors can be chained, meaning that you can do
#!as var m = [[1, 2], [3, 4]]; var v = m[0][1]; // v == 2
m[0]
into an intermediate variable.
"in" operator
variable_instance_
functions are supported in the scripting language, meaning that you can do
#!as trace(variable_instance_exists(self, "some")); // 0 or 1, depending on whether variable exists variable_instance_set(self, "some", "hi"); trace(variable_instance_get(self, "some")); // "hi"
variable_instance_exists
is a pretty long name for something that you may want to do often, another thing that is supported is a (variable name) in (instance)
operator, meaning that you can do
#!as if ("time" in self) { // variable exists - increment it time += 1; } else { // variable does not yet exist - give it a default value time = 0; }
not in
:
#!pas if ('time' not in self) time = 0;
Lightweight objects
Sometimes you may want to group a bunch of values together, but without the hassle of creating-managing-destroying an instance. In such cases you may want to use lightweight objects instead:
#!as var q = { a: 1, b: "hi" }; trace(q); // { a: 1, b: "hi" } trace(q.b); // "hi" trace("a" in q); // 1
#!as 1 "hi" "a" "b" <id>
<id>
is a field pattern id for faster lookup)
Wait-instruction
One of the scripting language's most notable features is the wait-instruction.
To put it shortly, when executed, the program will pause for the given number of frames while the rest of the game continues executing. So,
#!as for (var i = 1; i <= 5; i++) { trace(i); wait 30; }
This allows to do lots of interesting things. For example, to make an explosive bullet for a custom weapon, you could simply wait
for projectile to be destroyed while tracking it's position:
#!as #define weapon_fire motion_add(gunangle, -4); weapon_post(6, -7, 5); // create and configure a projectile: var qx = x, qy = y; var q = instance_create(qx, qy, HeavyBullet); with (q) { team = other.team; motion_add(other.gunangle + random_range(-5, 5), 1); friction = -0.8; // gradual acceleration image_angle = direction; } // track projectile' position while it exists: while (instance_exists(q)) { qx = q.x + q.hspeed; qy = q.y + q.vspeed; wait 1; } // create an explosion at it's last position once it's gone: instance_create(qx, qy, SmallExplosion);
wait
is extremely useful for writing sequentially executing code without hassle.
Fork-instruction
Another notable language feature is the fork
instruction.
fork()
acts like a function that, when called, will create a copy of the currently running script. The copy will have it's own (copied) local variables, but will share global variables, arrays, and game context with the original; The copy will execute it's script and finish while the original will continue it's own way; The function returns true
to the copy and false
to the original. For a more visual example,
#!as if (fork()) { trace("fork"); } else trace("orig"); trace("post");
fork post orig post
wait
call into the copy however, the original would resume as soon as the copy pauses:
#!as if (fork()) { trace("fork"); wait 1; } else trace("orig"); trace("post");
fork orig post [from orig] [1 frame pause] post [from fork]
fork
is executing something involving wait
without interrupting the original program. For that you would insert an exit
statement in the end of fork
's branch to prevent it from executing the rest of the script. For example,
#!as if (fork()) { wait 10; trace("fork"); exit; } else trace("orig"); trace("post");
orig post [from orig] [10 frame pause] fork
#!as motion_add(gunangle, -4); weapon_post(6, -7, 5); for (var i = -15; i <= 15; i += 15) if (fork()) { var qx = x, qy = y; var q = instance_create(qx, qy, HeavyBullet); with (q) { team = other.team; motion_add(i + other.gunangle + random_range(-5, 5), 1); friction = -0.8; image_angle = direction; } while (instance_exists(q)) { qx = q.x + q.hspeed; qy = q.y + q.vspeed; wait 1; } instance_create(qx, qy, SmallExplosion); exit; }
fork
compliments wait
and even further extends what you can do with it.
In conclusion
While scripting language is overwhelmingly compatible with GML and you can write the code exactly the same way as you would in GameMaker, the new tricks that it brings can be used to do tasks even faster and easier.
Updated