Nox Script  3.0
 All Files Functions Variables Enumerations
Nox Script Documentation

Language Reference

Introduction

Welcome to Nox Script 3.0! This language is inspired by Pawn which is a scripting language with a C-like syntax. If you are familiar with C, then this will be very familiar to you.

// Hello world! example
void MapInitialize()
{
Print("Hello world!");
}

Types

There are four exposed types in Nox Script:

The int and float types are the same as C. The string type refers to a string in the string table. Lastly, the object type is used as an opaque type. It does not refer to an object in Nox! Types are strictly enforced to prevent errors.

In Nox Script, Nox objects are always referred to by their in-game ID which is an int. In addition, there are two keywords, self and other, that refer to the caller of the script and target of the script, respectively. In the API Reference, these will be referred to as SELF and OTHER.

The most common usage of the object type is when you are dealing with groups and waypoints. While these are technically integer IDs, Nox Script uses an opaque type for basic type checking and preventing you from performing operations on them. The only allowed operations are assignment (=), is-equal (==), and is-not-equal (!=).

void MapInitialize()
{
int thePlayer;
object waypoint;
thePlayer = GetHost();
waypoint = Waypoint("Waypoint1");
}

Operators

All of the standard arithmetic and comparison operators are supported on both int and float types. Bitwise operators are only allowed on int types. Additionally, string types support comparison operators, concat (+), and concat-assign (+=). Below is a complete list of operators and supported types:

Supported operators
Assignment=int, float, string, object
Concat Assignment+=string
Arithmetic Assignment+= -= *= /=int, float
Bitwise Assignment&= |= ^= <<= >>=int
Modulo Assignment%=int
Concatenation+string
Arithmetic+ - * /int, float
Modulo%int
Bitwise& | ^ = << >>int
Logical&& ||int
Equality== !=int, float, string, object
Comparison< > <= >=int, float, string

Literals

There are three types of literals: ints, floats, and strings. The syntax is similar to C.

An int-literal is either a decimal, hexadecimal, or octal number. A hexadecimal number starts with 0x, and a octal number starts with 0. There are additionally the keywords true and false, which are treated as 1 and 0 respectively.

A float-literal is a number of the form: 1.0 or 1.0e2. It must contain a dot, otherwise it may be interpreted as an int-literal, which may cause a type mismatch.

A string-literal is a C quoted string: "hello world". It may contain the usual C escape characters, for example: "This is a quote: \".". All string literals will be added to the string table during compilation.

Variables

Like C, all variables are statically typed when they are declared. In addition, a variable name must not conflict with any other name that is within scope. Variables that are declared outside of a function have a global scope, and they can be modified or used from any function. Variables inside a function have a block scope.

The basic syntax for variable declaration is: type name;.

You can also immediately assign a value using: type name = value;. If you assign a value to a global variable at declaration, then it must be a constant expresssion (e.g. it does not use any functions or variables).

Declaring a variable can only be done as a statement. It cannot be inside of an expression.

Arrays are also supported: type name [length];. The length must an integer number greater than 1. Arrays must be subscripted when they are used: name[index].

int RequiredGold = 100;
object Waypoints[32];
void MapInitialize()
{
int ContestOfficial = Object("ContestOfficial");
int i;
for (i = 0; i < 32; i += 1)
Waypoints[i] = Object("Waypoint" + IntToString(i + 1));
}

Functions

Functions are defined in the global scope and their names must not conflict with variable names or built-in names. Functions can have an return type and parameters. If a function does not return anything, then its return type must be the void keyword. Function parameters can be used just like normal variables.

The function declaration syntax is similar to C: type name(type paramName1, type paramName2, ...).

You can call functions and pass in arguments like C: name(arg1, arg2, ...). If a function returns a value, a function can be called in an expression. This syntax also applies to calling a built-in. Argument types are checked against the expected parameter types.

Some built-ins take a function as a parameter. This is the only situation where you can use a function as a value.

int RequiredGold = 100;
void MapInitialize()
{
int official = Object("ContestOfficial");
InitDialog(official);
}
void InitDialog(official)
{
SetDialog(official, "NORMAL", NullDialogStart, ContestOfficialDialogEnd);
}
void NullDialogStart()
{
}
void ContestOfficialDialogEnd()
{
if (GetAnswer() == 1)
{
if (GetGold(GetHost()) < RequiredGold)
{
Print("GeneralPrint:WishingWellNotEnoughGold");
}
else
{
RestoreHealth(GetHost(), GetHealingAmount(GetHost()));
}
}
}
int GetHealingAmount(object player)
{
return MaxHealth(player) - CurrentHealth(player);
}

Control Flow

The standard control flow constructs are present: if statements, for loops, and while loops. Additionally, you can use a goto statement and labels if necessary, but this is heavily discouraged.

if (cond1)
{
}
else if (cond2)
{
}
else
{
}

An if statement can have an optional else statement. You can chain these to produce an else-if statement:

for (initialization; condition; afterthought)
{
}

A for loop has 3 parts, each is optional. The initialization happens before any loop code. It must be an expression (e.g. it cannot be used to declare a variable). The condition is checked, and exits the loop if false. And the afterthought is performed every time the loop ends and repeats.

while (condition)
{
}

A while loop has a condition that is checked, and exits the loop if false. The condition is required.

Both for loops and while loops can be controlled by keywords. A break; will exit the loop immediately. A continue; will cause the loop to repeat immediately.

goto A;
...
A:
print("A");

A goto statement can be used to immediately start executing from a label. Labels have function scope, so you can only goto a local label. Using a goto is heavily discouraged.

void foo()
{
return;
}
int bar()
{
return 1 + 2;
}

A return statement is used to immediately exit the current function. It is also required when the function has a return type.

API Reference

Built-in Functions

Use builtins.h to find the function you are interested in. These functions have been renamed from previous versions:

Examples

Below are some examples inspired by scripts in official Nox maps. These are just snippets, so they are not sufficient by themselves.

// some functions from G_Temple
int goodiePits[32];
object goodiePitExitWalls;
object elevatorWalls6;
int isFONTrapOn;
int fonTrapOrigin1;
object fonTrapTarget1;
void InitializeGoodiePits()
{
int i;
for (i = 0; i < 32; i += 1)
{
goodiePits[i] = Object("GoodiePit" + IntToString(i + 1));
}
goodiePitExitWalls = WallGroup("GoodiePitExitWalls");
elevatorWalls6 = WallGroup("ElevatorWallgroup06");
}
void OpenGoodiePit(int i)
{
ObjectOn(goodiePits[i - 1]);
}
void GoodiePit1()
{
ObjectOff(self);
OpenGoodiePit(1);
}
void FireFONTrap01()
{
ObjectOff(self);
Print("GeneralPrint:MsgTrapOn");
isFONTrapOn = true;
"SPELL_FORCE_OF_NATURE",
fonTrapOrigin1,
GetWaypointX(fonTrapTarget1),
GetWaypointY(fonTrapTarget1));
SecondTimer(5, FONTrap01Loop);
}
void FONTrap01Loop()
{
if (isFONTrapOn)
{
"SPELL_FORCE_OF_NATURE",
fonTrapOrigin1,
GetWaypointX(fonTrapTarget1),
GetWaypointY(fonTrapTarget1));
SecondTimer(5, FONTrap01Loop);
}
}
void InitializeFONtraps()
{
fonTrapOrigin1 = Object("FON_Origin01");
fonTrapTarget1 = Waypoint("FON_Target01");
}
void MapInitialize()
{
InitializeGoodiePits();
InitializeFONtraps();
}
// function from Con02A (adapted as an example)
void ContestGuardDialogEnd()
{
int hasBow = false;
int item;
for (item = GetLastItem(GetHost()); item != 0; item = GetPreviousItem(item))
{
if (HasClass(item, "WEAPON") && HasSubclass(item, "BOW"))
{
hasBow = true;
break;
}
}
int gold = GetGold(GetHost());
if (gold < 100)
{
TellStory("SwordsmanHurt", "Con02A:NotEnoughGold");
}
else if (hasBow == false)
{
TellStory("SwordsmanHurt", "Con02a:NoBow");
}
else
{
ChangeGold(GetHost(), -100);
}
}