Jump to content

A Guide to Angelscript


Recommended Posts

So I realize that most people probably don't know a whole lot about C or Angelscript, so I'm taking the time to write a guide, slowly but surely. (If @@Circa or someone would like to pin this, this would be great.)


As with all information, you can find the complete guide to Angelscript here.


I'd like to break this down into information that's specific to JK2:HD as well as make it a bit easier to understand (as I can personally attribute to this stuff being completely fscking badly written at times).



Basic Syntax

First, I want to get some basic syntax out of the way. Angelscript is very similar to C and C++, and the syntax as such is pretty much the same.

// Anything after a // is considered a comment, and is not processed by the system.
// Use these to help others understand your code better, or to temporarily disable parts of code ("commenting out")
/* Anything between this notation is also considered a comment. */
This syntax for comments can span multiple lines
int something = 5; // All basic lines must end in a semicolon.
if(something == 5) // Parentheses must be closed off
    something = 6;
if(something == 6) {
    something = 7;
} // Likewise, { must be followed by a } at some point.
// You can't simply put a } or a ) somewhere either. These will cause the compiler to become confused as it expects a ( or { before them


Angelscript, unlike ICARUS, relies heavily on the concept of variables. There's a few basic types that you should familiarize yourself with.

  • int: The basic number storage unit. Has a maximum size of ~-2 billion to ~2 billion.
  • float: Stores a "floating point" number, in other words, a decimal number such as 4.05 or 2.15. This can also be negative.
  • bool: Stores either a 0 or a 1, representing "true" or "false"
  • string: Stores a number of characters forming words or sentences. For example, "I have a lightsaber!" or "This is a string" or even "cat".

There's also a few advanced types and modifiers to the original types:

  • int modifiers: int can be modified to change its maximum storage capacity. As you'll recall, an int can have between -2 billion and 2 billion as values. But there's some reasons why you might want to change this to be smaller or larger. By specifying a power of 2 between 8 and 64, you can change the int's bit size. For example, int8 and int16, which are both smaller than the default amount (-128 to 127 and -32768 to 32767 respectively). There's also int32, which is the same as regular int, as well as int64 which is much, much larger than a regular int. I would avoid using int64, int16 and int8 unless you really need them (such as saving/loading files and networking stuff), so for the most part this isn't really needed. By placing a letter 'u' before 'int', you can specify that the variable is unsigned, or is never negative. This also effectively doubles the maximum size. For instance, uint8 now goes from 0 to 255, and uint32 now goes from 0 to 4 billion. You must specify a size with uints.
  • const: By placing the keyword 'const' before a variable, you specify that the variable cannot be changed. This can be good for a number of reasons, mostly for others understanding your code. You should probably use const whenever you can.
  • double: This is a different type, similar to float. However it uses 64 bits instead of 32 and is therefore more precise.
  • void: This is a unique type which we will discuss later.

How about a few examples?

int x = 4; // Define a variable named 'x' of type int with a starting value of 4
float y = 4.5; // Define a variable named 'y' of type float with a starting value of 4.5
bool z = true; // Define a bool named 'z' with a starting value of 'true'


There is another specific type of variable in Angelscript, called objects. These have a variety of properties, but it's important for the moment to consider these as sorts of containers for other variables. For right now, I won't get too detailed into these, but there's a few objects which you will see throughout the code (such as gentity_t) and it's important to recognize them.



Variable Naming

There's a few things that should be noted about variables. First, you cannot start a variable with a number (so 1x would be illegal, but x1 is legal). Variables are also case sensitive. X1 is an entirely different variable from x1. There's also a bunch of names that you can't use as variable names, these are covered here:



double else
import in
namespace not







We can also do some math:

int x = 6;
int y = 7;
x = y; // x is now 7
x *= y; // x = 7, so 7*7 = 49
x -= y; // x = 49, so 49-7 = 42
y += 10; // y is now 17
x /= 7; // x = 42, so 42/7 = 6
x++; // Increment x by one, so x is now 7
x--; // x is 6 again since we're decreasing by one


Functions are chunks of code which get executed by other code. Consider this function:

void PrintSomething(string whatToPrint) {
   Com_Print(whatToPrint); // Print the value of whatToPrint in the console

All this function does is print something in the console, based on what we give to it. While it's really not a good idea to do this per se (why not just use Com_Print?), it does demonstrate the basic idea of a function. You'd then call this function thusly:

string somethingWeShouldPrint = "Something\n";

Did you see the void at the beginning of the function? This refers to the return type. You can place a return at any point in the function to "get out of the function" so to speak.

void dummy(int someargument) {
    int something = 6;
    something = 7; // Everything after the return; doesn't occur, so this line doesn't get executed at all.

So what is a return type exactly? Well, a function can return a value based on what its return type is:

int dummy2(int someargument) {
    int something = 6;
    return something;
int value = dummy2(0);
// 'value' now equals 6, since we returned a 6

What about the bit in the ()? Well, these are called parameters. We can pass along some parameters (or none at all!) and the code will use these as variables in the function:

int dummy3(int someargument) {
    return someargument;
int value = dummy3(3);
// Value now equals 3, since we passed along a 3, and that got returned to us.

Flow of control: if/else

If you're familiar with ICARUS, you might already know of if/else constructs. if/else is a big construct in nearly every programming language, save for some odd ones like Haskell. When we do an if/else, we're essentially computing a binary instruction which is either true or false. So for instance, if we were to compare:

int x = 3;
int y = 4;
if(x == y)
    x = 5; // TIP: you do not need to specify {} with if/else if there is only one line in the block
else {
   y = 6; // However if there is more than one line, you must always use {}
   x = 6;

What happens in this chunk of code? Well, x gets compared to y (note the double == as opposed to =), and if this evaluates to true, the block within gets executed. If not, then the else{} block gets executed. else{} is entirely optional.

Here's a slightly more trivial example:

bool b = true;
    Com_Print("b is true!\n");
    Com_Print("b is false!\n");

What's going on here? We're evaluating what's going on in the (), which in this case happens to be "true" since b equals true. So in this particular example, "b is true!" always gets printed in the console.

Okay, here's an even more basic example than that:

    Com_Print("Here's some silly line that always gets printed\n");
    Com_Print("Here's some silly line that never gets printed\n");

I want to compound this with another concept, that of else if:

int x = 6;
int y = 10;
if(x == 7)
    Com_Print("This line doesn't get executed...\n");
else if(y == 10)
    Com_Print("This one does however!\n");
    Com_Print("Since the else if block got executed, we didn't get to this point.\n");




vec3_t - Vectors

Used to represent position, direction, etc in 3D space.

float x - x position
float y - y position
float z - z position

entityState_t - Entity State

Stores savegame information specific to entities

int weapon - currently equipped weapon

playerState_t - Player State

Stores savegame information specific to the player

int accuracy_shots - total number of shots fired
vec3_t viewangles

gclient_t - Client

Stores savegame information specific to NPCs and player

playerState_t ps

gentity_t - Entity

Basic unit of an entity. Can be any type (NPC, player, projectile, ...)

gclient_t client
entityState_t s
vec3_t mins - Bounding box
vec3_t maxs - Bounding box
int damage - Damage dealt (if any)
int dflags - Damage flags (if any)
int methodOfDeath - Sets method of death (not really used all that much in SP)
int clipMask - What the entity collides with
int bounceCount - Bouncing (specific to projectiles)


void CalcMuzzlePoint(gentity_t@ ent, vec3_t fwd, vec3_t right, vec3_t up, vec3_t muzzle, float lead_in)

Calculates an entity's muzzle point, and stores the values in fwd, right, up, and muzzle. lead_in is not used (it's for xbox-related code for autoaiming I think)

void Com_Print(string message)

Prints a message to the console.

int Com_Clampi(int min, int max, int value)
float Com_Clamp(float min, float max, float value)

Constrains value between min and max and returns the result

int Com_AbsClampi(int min, int max, int value)
float Com_AbsClamp(float min, float max, float value)

Contrains value between min/max, returning the result. Min/Max/Value all use their absolute values (always positive)

int Q_irand(int min, int max)
float Q_flrand(float min, float max)

Returns a random value between min and max (inclusive)

float sin(float value)
float cos(float value)

Standard trigonometry functions

int GetWeaponDamage(int weapon)

Returns the damage that the weapon does (from the .json file)

gentity_t@ CreateMissile(vec3_t start, vec3_t forward, int velocity, int life, gentity_t@ owner)

Creates a missile, returning the gentity_t handle of the missile itself.

void WP_TraceSetStart(gentity_t@ ent, vec3_t start, vec3_t mins, vec3_t maxs)

Given the entity and its start, mins and maxs vectors, sets the start point of the entity (this is to make sure that it doesn't go through walls in some situations)


Global Variables


- Coordinates for weapon firing -
vec3_t wpFwd
vec3_t wpRight
vec3_t wpUp
vec3_t wpMuzzle
vec3_t vec3_origin - variable that holds (0, 0, 0)
Stoiss, therfiles and Circa like this
Link to comment
This topic is now closed to further replies.
  • Create New...