Nasal library

From FlightGear wiki
Jump to navigation Jump to search

This page documents the global library functions and variables of FlightGear's built-in scripting language, Nasal. This includes core library functions, which were included in Nasal before its integration into FlightGear, the extension functions, which have been subsequently added, and are specifically designed for FlightGear, and the global variables, which are conversion variables, added with extension functions, for converting between units. The relevant folders in Git are:

All these functions and variables are in the global namespace, that is, they are directly accessible (e.g., one can call magvar() instead of namespace.magvar()). However, if a namespace must be used, globals is the correct namespace, but using it is not recommended. For a more complete explanation, see Nasal Namespaces in-depth.

Tip  Copy & paste the examples into your Nasal Console and execute them to see what they do.

Core library functions

This is the list of the basic core library functions. Most of these functions were part of the original Nasal library (before its integration in to FlightGear), while some have been added or changed over time. See also:

append()

append(vector, element[, element[, ...]]);

Source

This function appends, or adds, the given element(s) to the end of the vector given in the first argument. Returns the vector operated on.

vector
The vector to which the arguments will be appended.
element
An element to be added to the vector.

Examples

var vector = [1, 2, 3]; # Initialize the vector
append(vector, 4); # Append the number 4 to the end of the vector
debug.dump(vector); # Print the contents of the vector
var vector = [1, 2, 3]; # Initialize the vector
append(vector, 4, 5, 6); # Append the numbers 4, 5, and 6 to the end of the vector
debug.dump(vector); # Print the contents of the vector

bind()

bind(function, locals[, outer_scope]);

Source

This creates a new function object. A function in Nasal is three things: the actual code, a hash/namespace of local variables available to the function namespace, and the closure object of that namespace. These correspond to the three arguments respectively.

function
Function to evaluate.
locals
Hash containing values that will become the namespace (first closure) for the function.
outer_scope
Optional function which is bound to the next closure. This can be bound to yet another, making a linked list.

Example

# This is a namespace/hash with a single member, named "key," which is initialized to 12 
var Namespace = {
    key: 12
};

# This is different namespace/hash containing a function
# dividing a variable "key" (which is unavailable/nil in this namespace) by 2
var AnotherNamespace = {
    ret: func {
        key /= 2;
    }
};

# To see that key is not available, try to call AnotherNamespace.ret() first
call(AnotherNamespace.ret, [], nil, nil, var errors = []);
if(size(errors)){
    print("Key could not be divided/resolved!");
    debug.printerror(errors);
}

# Associate the AnotherNamespace.ret() function with the first namespace
# so that "key" is now available
var function = bind(AnotherNamespace.ret, Namespace);

# Invoke the new function
function();

# Print out the value of Namespace.key
# It was changed to 12 from 6 by AnotherNamespace.ret()
print(Namespace.key);

call()

call(func[, args[, me[, locals[, error]]]);

Source

Calls the given function with the given arguments and returns the result. This function is very useful as it allows much more control over function calls and catches any errors or die() calls that would normally trigger run-time errors cancelling execution of the script otherwise.

func
Function to execute.
args
Vector containing arguments to give to the called function.
me
me reference for the function call (i.e., for method calls). If given, this will override any me value existing in the namespace (locals argument).
locals
A hash with key/value pairs that will be available to the called function, typically used as the namespace for the function to be called.
error
A vector to append errors to. If the called function generates an error, the error, place, and line will be written to this. These errors can be printed using debug.printerror() .

Examples

# prints "Called from call()"
call(func {
    print("Called from call()");
});
# prints "a = 1 : b = 2
call(func(a, b){
        print("a = ", a, " : b = ", b);
    },
    [1, 2]
);
var Hash = {
    new: func {
        var m = { parents: [Hash] };

        m.el1 = "string1";
        m.el2 = "string2";

        return m;
    }
};

# prints "me.el1 = string1", then "me.el2 = string2" on the next line
call(func(a, b){        
        print("me.el", a, " = ", me["el" ~ a]);      
        print("me.el", b, " = ", me["el" ~ b]);
    },
    [1, 2],
    Hash.new()
);
# prints the value of math.pi
call(func {
        print(pi);
    }, nil, nil, 
    math
);
call(func {
        print(math.ip); # math.ip doesn't exist
    }, nil, nil, nil,
    var errs = []
);
debug.printerror(errs); # The error is caught and printed using debug.printerror()

caller()

caller([level]);

Source

Returns a vector containing a record from the current call stack. The level numbering starts from the currently executing function (level 0). Level 1 (the default) is the caller of the current function, and so on.

The result is a four-element vector containing [0] a hash of local variables, [1] the function object, [2] the full source file name (incl. path) and [3] the line number.

level
Optional integer specifying the stack level to return a result from. Defaults to 1 (i.e. the caller of the currently executing function).

Examples

var myFunction = func(a, b){
    debug.dump(caller(0)[0]); # prints a hash of local variables, including arguments a and b
    return 2 * 2;
};

print("2 x 2 = ", myFunction(2, 2));
var get_arg_value = func(){
    print("Argument to myFunc = ", caller(1)[0]['a']); # print the value of myFunc's single argument, using caller()
};

var myFunc = func(a){
    get_arg_value();
};

myFunc(3);

This is a real example taken from fgdata/Nasal/canvas/MapStructure.nas. Function r() (above the TODOs) returns a hash with the key/value pairs as per its arguments. For example, something like this is returned: { name: "<name>", vis: 1, zindex: nil }.

var MapStructure_selfTest = func() {
	var temp = {};
	temp.dlg = canvas.Window.new([600,400],"dialog");
	temp.canvas = temp.dlg.createCanvas().setColorBackground(1,1,1,0.5);
	temp.root = temp.canvas.createGroup();
	var TestMap = temp.root.createChild("map");
	TestMap.setController("Aircraft position");
	TestMap.setRange(25); # TODO: implement zooming/panning via mouse/wheel here, for lack of buttons :-/
	TestMap.setTranslation(
		temp.canvas.get("view[0]")/2,
		temp.canvas.get("view[1]")/2
	);
	var r = func(name,vis=1,zindex=nil) return caller(0)[0];
	# TODO: we'll need some z-indexing here, right now it's just random
	# TODO: use foreach/keys to show all layers in this case by traversing SymbolLayer.registry direclty ?
	# maybe encode implicit z-indexing for each lcontroller ctor call ? - i.e. preferred above/below order ?
	foreach(var type; [r('TFC',0),r('APT'),r('DME'),r('VOR'),r('NDB'),r('FIX',0),r('RTE'),r('WPT'),r('FLT'),r('WXR'),r('APS'), ] ) 
		TestMap.addLayer(factory: canvas.SymbolLayer, type_arg: type.name,
					visible: type.vis, priority: type.zindex,
		);
}; # MapStructure_selfTest

chr()

chr(code);

Source

Returns a character as per the single argument. Extended ASCII is supported (see http://www.asciitable.com/ for a list of supported characters), although this may vary between different systems. For a list of the most commonly used characters, see the ASCII printable code chart This is a link to a Wikipedia article (Dec column). The following table lists supported control characters, along with their equivalent control characters in Nasal strings.

Note  In Nasal, only strings enclosed with double-quotes ("string") supports control chracters. Strings in single quotes ('string') do not.
Code Name Equivalent to
10 Newline This is a link to a Wikipedia article \n
9 Horizontal tab This is a link to a Wikipedia article \t
13 Carriage return This is a link to a Wikipedia article \r
code
Integer character code for the desired glyph.

Examples

print("Code 65 = ", chr(65)); # prints "Code 65 = A"

This example displays all of the characters in a list, in the format Code n = >char<, n being the index, and char being the character.

for(var i = 0; i <= 255; i += 1){
    print("Code ", i, " = >", chr(i), "<");
}

closure()

closure(func[, level]);

Source

Returns the hash table containing the lexical namespace of the given function. The level numbering start with level 0 being the namespace of func.

func
Function to evaluate.
level
Optional integer specifying the scope level. Defaults to 0 (the namespace of func).

Example

var get_math_e = func {
    return e; # return the value of math.e
}

var myFunction = bind(get_math_e, math); # bind get_math_e to the math namespace, so that math.e is immediately available to get_math_e
debug.dump(closure(myFunction)); # print the namespace of get_math_e

print(myFunction());

cmp()

cmp(a, b);

Source

Compares two strings, returning -1 if a is less than b, 0 if they are identical and 1 if a is greater than b.

a
First string argument for comparison.
b
Second string argument for comparison.

Examples

print(cmp("1", "two")); # prints -1
print(cmp("string", "string")); # prints 0
print(cmp("one", "2")); # prints 1
print(cmp("string1", "string2")); # prints -1

compile()

compile(code[, filename]);

Source

Compiles the specified code string and returns a function object bound to the current lexical context. If there is an error, the function dies, with the argument to die() being filename.

code
String containing Nasal code to be compiled.
filename
Optional string used for error messages/logging. Defaults to <compile>

Examples

var myCode = 'print("hello");';
var helloFunc = compile(myCode, "myCode");
helloFunc();

compile is very convenient to support Nasal loaded from other files. For instance, PropertyList XML files (such as GUI dialogs) may contain embedded Nasal sections that need to be parsed, processed and compiled. For an example of how to do this, save the below XML code as $FG_ROOT/gui/dialogs/test.xml.

<?xml version="1.0"?>

<PropertyList>

<nasal><![CDATA[
print("You have FlightGear v", getprop("/sim/version/flightgear"));
]]></nasal>

</PropertyList>

Now, start FlightGear and execute this code in the Nasal Console.

# Build the path
var FGRoot = getprop("/sim/fg-root");
var filename = "/gui/dialogs/test.xml";
var path = FGRoot ~ filename;

var blob = io.read_properties(path);
var script = blob.getValues().nasal; # Get the nasal string

# Compile the script.  We're passing the filename here for better runtime diagnostics 
var code = call(func {
    compile(script, filename);
}, nil, nil, var compilation_errors = []);

if(size(compilation_errors)){
    die("Error compiling code in: " ~ filename);
}

# Invoke the compiled script, equivalent to code(); 
# We're using call() here to detect errors:
call(code, [], nil, nil, var runtime_errors = []);

if(size(runtime_errors)){
    die("Error calling code compiled loaded from: " ~ filename);
}

contains()

contains(hash, key);

Source

Returns 1 (True) if the hash contains the specified key, or 0 (False) if not.

hash
The hash to search in.
key
The scalar to be searched for, contained as a key in the hash.

Example

# Initialize a hash
var hash = {
    element: "value"
};
print(contains(hash, "element") ? "Yes" : "No"); # This will print "Yes"
print(contains(hash, "element2") ? "Yes" : "No"); # This will print "No"


contains()

Note  The feature documented below (Vector support) is only available as of SimGear commit ee39abbd3b70c9b6d5e3a1c4ccedddaac1a92b11 see MR #305 (fgdata)
contains(vector, item);

Source

Returns 1 (True) if the vector contains the specified item, or 0 (False) if not.

vector
The vector to search in.
item
The object to be searched for in the vector.

Example

# Initialize a vector
var vec = ["element", "foo"];
print(contains(vec, "element") ? "Yes" : "No"); # This will print "Yes"
print(contains(vec, "element2") ? "Yes" : "No"); # This will print "No"

delete()

delete(hash, key);

Source

Deletes the key from the hash if it exists. Operationally, this is NOT identical to setting the hash value specified by the key to nil as the key will stay in the hash (at least for a while). This variant potentially frees storage by deleting the reference to the key and by shrinking the hash. Returns the hash that has been operated on.

hash
The hash from which to delete the key.
key
The scalar to be deleted, contained as a key in the hash.

Example

# Initialize the hash
var hash = {
    element1: "value1",
    element2: "value2"
};
delete(hash, "element1"); # Delete element1
debug.dump(hash); # prints the hash, which is now minus element1

die()

die(error);

Source

Terminates execution and unwinds the stack. The place and the line will be added to the error. This invokes the same internal exception handler used for internal runtime errors. Use this to signal fatal errors, or to implement exception handling. The error thrown (including internal runtime errors) can be caught with call() .

error
String describing the error.
Note This parameter is technically optional, but it is highly recommended to use it.

Example

print("Will print");
die("Don't go any further!"); 
print("Won't print"); # Will not be printed because die() stops the process

find()

find(needle, haystack);

Source

Finds and returns the index of the first occurrence of the string needle in the string haystack, or -1 if no such occurrence was found.

needle
String to search for.
haystack
String to search in.

Examples

print(find("c", "abcdef")); # prints 2
print(find("x", "abcdef")); # prints -1
print(find("cd", "abcdef")); # prints 2

ghosttype()

ghosttype(ghost);

Source

Returns a string containing either a descriptive name of a ghost (a raw C/C++ object), or a unique id (the pointer to the C/C++ naGhostType instance) if no name has been set. Ghost is an acronym that stands for Garbage-collected Handle to OutSide Thingy.

ghost
Ghost to return a description for.

Example

print(ghosttype(airportinfo())); # prints "airport"

id()

id(object);

Source

Returns a string containing information on the type and ID of the object provided in the single argument. The information is returned in the form of <type>:<id>, where <type> is the type of object, and <id> is the ID.

object
Can be either of a string, a vector, a hash, a code, a function, or a ghost.

Example

print(id("A")); # prints "str:000000001624A590"

int()

int(number);

Source

Returns the integer part of the numeric value of the single argument, or nil if none exists.

number
Number or string with just a number in it to return an integer from.

Examples

print(int(23)); # prints "23"
print(int(23.123)); # prints "23"
debug.dump(int("string")); # prints "nil"

keys()

keys(hash);

Source

Returns a vector containing the list of keys found in the single hash argument.

hash
The hash to return the keys from.

Example

# Initialize a hash
var hash = {
    element1: "value",
    element2: "value"
};
debug.dump(keys(hash)); # print the vector

left()

left(string, length);

Source — Version added: FG 2.12 (commit)

Returns a substring of string, starting from the left.

string
String to return part of.
length
Integer specifying the length of the substring to return.

Example

print(left("string", 2)); # prints "st"

num()

num(number);

Source

Returns the numerical value of the single string argument, or nil if none exists.

number
String with just a number in it to return a number from.

Examples

print(num("23")); # prints "23"
print(num("23.123")); # prints "23.123"
debug.dump(num("string")); # prints "nil"

pop()

pop(vector);

Source

Removes and returns the last element of the single vector argument, or nil if the vector is empty.

vector
Vector to remove an element from.

Examples

var vector = [1, 2, 3];
pop(vector);
debug.dump(vector); # prints "[1, 2]"
var vector = [1, 2, 3];
debug.dump(pop(vector)); # prints "3"
var vector = [];
debug.dump(pop(vector)); # prints "nil"

right()

right(string, length);

Source — Version added: FG 2.12 (commit)

Returns a substring of string, starting from the right.

string
String to return part of.
length
Integer specifying the length of the substring to return.

Example

print(right("string", 2)); # prints "ng"

setsize()

setsize(vector, size);

Source

Sets the size of a vector. The first argument specifies a vector, the second a number representing the desired size of that vector. If the vector is currently larger than the specified size, it is truncated. If it is smaller, it is padded with nil entries. Returns the vector operated upon.

vector
The vector to be operated on.
size
The desired size of the vector in number of entries.

Examples

var vector = [1, 2, 3]; # Initialize a vector
setsize(vector, 4);
debug.dump(vector); # print the vector
var vector = [1, 2, 3]; # Initialize a vector
setsize(vector, 2);
debug.dump(vector); # print the vector

size()

size(object);

Source

Returns the size of the single argument. For strings, this is the length in bytes. For vectors, this is the number of elements. For hashes, it is the number of key/value pairs. If the argument is nil or a number, this error will be thrown: object has no size().

object
Object to find the size of. Must be a string, a vector or a hash.

Examples

var string = "string";
print(size(string)); # prints "6"
var vector = [1, 2, 3];
print(size(vector)); # prints "3"
var hash = {
    element1: "value1",
    element2: "value2",
    element3: "value3"
};
print(size(hash)); # prints "3"

sort()

sort(vector, function);

Source

Returns a vector containing the elements in the input vector sorted in according to the rule given by function. Implemented with the ANSI C qsort() , sort() is stable. This means that if the rules in the first example are used, equal elements in the output vector will appear in the same relative order as they do in the input. It is run in a loop, so function is run several times.

vector
Input vector to sort.
function
Function according to which the elements will be sorted by. It should take two arguments and should return one of 1, 0, or -1.
Return value Meaning
less than 0 first argument should go before second argument
0 first argument equals second argument
greater than 0 first argument should go after second argument

Examples

This example sorts elements from smallest to greatest.

var sort_rules = func(a, b){
    if(a < b){
        return -1; # A should before b in the returned vector
    }elsif(a == b){
        return 0; # A is equivalent to b 
    }else{
        return 1; # A should after b in the returned vector
    }
}
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints "[1, 2, 3, 4, 5, 6]"

This example sorts elements from greatest to smallest.

# Outputs the elements in reverse order (greatest to smallest)
var sort_rules = func(a, b){
    if(a < b){
        return 1; # -1 in the above example
    }elsif(a == b){
        return 0;
    }else{
        return -1; # 1 in the above example
    }
}
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints "[6, 5, 4, 3, 2, 1]"

This example sorts a vector of strings (runways for example) from smallest to greatest.

var runways = ["09R","27R","26L","09L","15"];
var rwy = sort(runways,func(a,b) cmp(a,b));
debug.dump(rwy); # prints ['09L','09R','15','26L','27R']

split()

split(delimiter, string);

Source

Splits the input string into a vector of substrings bounded by occurrences of the delimiter substring. See string.join().

delimiter
String that will split the substrings in the returned vector.
string
String to split up.

Examples

debug.dump(split("cd", "abcdef")); # prints "['ab', 'ef']"
debug.dump(split(".", "3.2.0")); # prints "[3, 2, 0]"
debug.dump(split("/", "path/to/file")); # prints "['path', 'to', 'file']"

sprintf()

sprintf(format[, arg[, arg, [...]]]);

Source

Creates and returns a string formatted using ANSI C vsnprintf() [1]. Below is a table of supported format specifiers.

%[flags][width][.precision]specifier
Flags
Flag Output
+ Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers. By default, only negative numbers are preceded with a - sign.
space Prefixes non-signed numbers with a space.
- Left-align the output of this placeholder (the default is to right-align the output) when the width option is specified.
0 Use 0 instead of spaces to pad a field when the width option is specified.
# Used with o, x or X specifiers the value is preceded with 0, 0x or 0X respectively for values different than zero. Used with e, E and f, it forces the written output to contain a decimal point even if no digits would follow. By default, if no digits follow, no decimal point is written. Used with g or G the result is the same as with e or E but trailing zeros are not removed.
Width
Integer specifying the minimum number of characters to be returned. This includes the decimal point and decimal fraction as well as + or - signs.
Precision
Integer preceded by a dot specifying the number of decimal places to be written.
Specifiers
Specifier Output
d, i Signed decimal number.
s A string
% Percent (%) character.
c A single character assigned to a character code, the code given in an integer argument. See http://www.asciitable.com/ for a list of supported characters and their codes.
o Unsigned integer as an octal number.
u Unsigned decimal integer.
x, X Unsigned integer as a hexadecimal number. If x is used, any letters in the number are lowercase, while X gives uppercase.
e, E Double value in scientific notation (i.e., [-]ddd.ddde[+/-]ddd), with an exponent being denoted by e or E depending on whether an upper or lowercase is used respectively.
f Floating-point number, in fixed decimal notation, by default with 6 decimal places.
F Appears to be available[2], but doesn't work.
g, G Double in either normal or exponential notation, whichever is more appropriate for its magnitude. g uses lower-case letters, G uses upper-case letters. This type differs slightly from fixed-point notation in that insignificant zeroes to the right of the decimal point are not included. Also, the decimal point is not included on whole numbers.
format
String specifying the format. Can be used with or without a format specifiers. See below for examples.
arg
Argument specifying a value to replace a format placeholder (such as %d) in the format string. Not required if there are no format specifiers.

Examples

print(sprintf("%i", 54)); # prints "54"
print(sprintf("Pi = %+.10f", math.pi)); # prints "Pi = +3.1415926536"
print(sprintf("%6d", 23)); # prints "    23"
print(sprintf("%06d", 23)); # prints "000023"
var FGVer = getprop("/sim/version/flightgear");
print(sprintf("You have FlightGear v%s", FGVer)); # prints "You have FlightGear v<your version>"
print(sprintf("Hexadecimal 100000 = %X", 100000)); # prints "Hexadecimal 100000 = 186A0"
print(sprintf("Hexadecimal 100000 = %x", 100000)); # prints "Hexadecimal 100000 = 186a0"
print(sprintf("Code 65 is %c", 65)); # prints "Code 65 is A"
print(sprintf("%e", 54)); # prints "5.400000e+001"
print(sprintf("%E", 54)); # prints "5.400000E+001"
print(sprintf("%o", 54)); # prints "66"
print(sprintf("50%% of 100 is %i", 100 / 2)); # prints "50% of 100 is 50"
print(sprintf("%.2f", 1.4));   #prints "1.40"
print(sprintf("%.1f", 1.4));   #prints "1.4"
print(sprintf("% 4.1f", 1.4)); #prints " 1.4"
print(sprintf("%04.1f", 1.4)); #prints "01.4"
print(sprintf("% 6.1f", 1.4)); #prints "   1.4"
print(sprintf("%06.1f", 1.4)); #prints "0001.4"

streq()

streq(a, b);

Source

Tests the string values of the two arguments for equality. This function is needed because the == operator (see Nasal Operators) tests for numeric equality first. If either or both the arguments are not strings, 0 (False) will be returned. Returns either 0 (False) or 1 (True).

Note  This function is rarely required in typical code.
a
First argument for testing equality.
b
Second argument for testing equality.

Examples

print(streq("0", "0")); # prints "1" (True)
print(0 == 0.0); # prints "1" (True)
print(streq("0", "0.0")); # prints "0" (False)

substr()

substr(string, start [, length]);

Source

Similar the subvec() , but operates on strings. Computes and returns a substring. The first argument specifies a string, the second is the index of the start of a substring, the optional third argument specifies a length (the default is to return the rest of the string from the start).

string
String to return a substring from.
start
Integer specifying the start of a substring. Negative values specify a position from the end of the string.
length
Optional argument specifying the length of the substring. Defaults to the end of the string.

Examples

print(substr("abcde", 1, 3)); # prints "bcd"
print(substr("abcde", 1)); # prints "bcde"
print(substr("abcde", 2, 1)); # prints "c"
print(substr("abcde", -2)); # prints "de"
print(substr("abcde", -3, 2)); # prints "cd"

subvec()

subvec(vector, start[, length]);

Source

Returns a sub-range of a vector. The first argument specifies a vector, the second a starting index, and the optional third argument indicates a length (the default is to the end of the vector).

vector
The vector to take the sub-vector from.
start
The starting point of the sub-vector within the given vector.
length
Optional argument specifying the length of the sub-vector, from the starting point.

Notes:

  • Omitting the vector and start arguments is not an error (possibly it should be) but the return value is nil.
  • A negative start argument is an error. This seems wrong. Perhaps the language designer could comment.
  • A value of start greater than size(vector) causes an error. A value equal to size(vector) returns an empty vector.
  • If the value of length is greater than size(vector) - start then it is ignored. That is, all elements from start to the end of vector are returned. If length is zero then an empty vector is returned. A negative value of length causes an error.

Examples

var vector = [1, 2, 3];
debug.dump(subvec(vector, 0)); # prints "[1, 2, 3]"
var vector = [1, 2, 3];
debug.dump(subvec(vector, 1)); # prints "[2, 3]"
var vector = [1, 2, 3];
debug.dump(subvec(vector, 1, 1)); # prints "[2]"

typeof()

typeof(object);

Source

Returns a string indicating the whether the object is nil, a scalar (number or string), a vector, a hash, a function, or a ghost.

object
Object to return the type of.

Examples

var object = nil;
print(typeof(object)); # prints "nil"
var object = "Hello world!";
print(typeof(object)); # prints "scalar"
var object = math.pi;
print(typeof(object)); # prints "scalar"
var object = [1, 2, 3];
print(typeof(object)); # prints "vector"
var object = {};
print(typeof(object)); # prints "hash"
var object = func {};
print(typeof(object)); # prints "func"
var object = airportinfo();
print(typeof(object)); # prints "ghost"


Extension functions

The extension functions are global functions that have been added to Nasal since its integration into FlightGear. Unlike the core library functions, they are generally specifically designed to interact directly with FlightGear. Extension functions come from three source files:

abort()

abort();

Source

This function is a wrapper for the C++ abort() function. It simply aborts FlightGear with an error, which varies depending on the operating system. This function should not really be used; instead, please use the "exit" fgcommand, which will exit FlightGear more gracefully (see example below).

Examples

This example will immediately stop FlightGear with an error, such as "FlightGear has stopped working."

abort();

For exiting FlightGear in a better way, please use the following code:

fgcommand("exit");

abs()

abs(number);

Source

This simple function returns the absolute value of the provided number.

number
This argument is required and should be a number.

Examples

print(abs(1)); # prints "1"
print(abs(-1)); # prints "1"

aircraftToCart()

This new function in FG 2017.2.1 takes coordinates in aircraft structural coordinate system, and translate them into geocentric coordinates. Example for (5,6,7):

var pos = aircraftToCart({x: -5, y: 6, z: -7});
var coord = geo.Coord.new();
coord.set_xyz(pos.x, pos.y, pos.z);

Notice: x and z is inverted sign on purpose. if you want lat. lon, alt from that, just call: (degrees and meters)

coord.lat()
coord.lon()
coord.alt()

addcommand()

addcommand(name, code);

Source — Version added: FG 2.12 (commit)

This function enables the addition of a new custom fgcommand to FlightGear from within Nasal. An fgcommand created using this method can be used in exactly the same way as the built-in fgcommands. Also, an fgcommand created via this method will always return True or 1, like all other fgcommands.

name
This will become the name of the new fgcommand. Must be a string.
code
The code that will be executed when the fgcommand is run. Must be a function.

Examples

This example adds a new fgcommand and then runs it. Although it executes a simple print() statement, any valid Nasal code can be used.

addcommand("myFGCmd", func(node) {
    print("fgcommand 'myFGCmd' has been run.");
    props.dump( node );
});
fgcommand("myFGCmd", props.Node.new({foo:1, bar:2}) );

This example demonstrates how parameters are defined in a new fgcommand.

addcommand("myFGCmd", func(node){
    print(node.getNode("number").getValue()); # prints the value of "number," which is 12
});
fgcommand("myFGCmd", props.Node.new({"number": 12}));

airportinfo()

airportinfo();
airportinfo(type);
airportinfo(id);
airportinfo(lat, lon[, type]);

Source

Function for retrieval of airport, heliport, or seaplane base information. It returns a Nasal ghost; however, its structure is like that of a Nasal hash. The following information is returned:

  • parents: A vector containing a hash of various functions to access information about the runway. See flightgear/src/Scripting/NasalPositioned.cxx (line 2659) for full list.
  • lon: Longitude of the location.
  • lat: Latitude of the location.
  • has_metar: True or false depending whether the airport has a METAR code defined for it.
  • elevation: Elevation of the location in metres.
  • id: ICAO code of the airport (or ID of the seaplane base/heliport).
  • name: Name of the airport/heliport/seaplane base.
  • runways
    • <runway name>
      • id: Name of runway.
      • lat: Latitude of the runway.
      • lon: Longitude of the runway.
      • heading: Heading of the runway.
      • length: Length of the runway in metres.
      • width: Width of the runway in metres.
      • surface: Runway surface type.
      • threshold: Length of the runway's displaced threshold This is a link to a Wikipedia article in metres. Will return 0 if there is none.
      • stopway: Length of the runway's stopway (the area before the threshold) in metres. Will return 0 if there is none.
      • reciprocal: runway ghost of the reciprocal runway.
      • ils_frequency_mhz: ILS frequency in megahertz.
      • ils: navaid ghost of the ILS transmitter.
  • helipads
    • <helipad name>
      • id: Name of helipad.
      • lat: Latitude of the helipad.
      • lon: Longitude of the helipad.
      • heading: Heading of the helipad.
      • length: Length of the helipad in metres.
      • width: Width of the helipad in metres.
      • surface: Helipad surface type.
  • taxiways
    • <taxiway name>
      • id: Name of taxiway.
      • lat: Latitude of the taxiway.
      • lon: Longitude of the taxiway.
      • heading: Heading of the taxiway.
      • length: Length of the taxiway in metres.
      • width: Width of the taxiway in metres.
      • surface: Taxiway surface type.

Information is extracted in the same way as accessing members of a Nasal hash. For example:

# prints to lengths of the runways of the nearest airport in feet and metres
var info = airportinfo();
print("-- Lengths of the runways at ", info.name, " (", info.id, ") --");
foreach(var rwy; keys(info.runways)){
    print(rwy, ": ", math.round(info.runways[rwy].length * M2FT), " ft (", info.runways[rwy].length, " m)");
}

Note that searches for locations that are a long way away (e.g., the nearest seaplane base to the middle of the Sahara) may cause FlightGear to pause for an amount of time.

id
The ICAO code of an airport to retrieve information about.
type
When this argument is used, the function will return the closest airport of a certain type. Can be one of "heliport," "seaport," or "airport" (default).
Note Running this function without any parameters is equivalent to this:
airportinfo("airport");

lat and lon
When these parameters are used, the function will return information on the nearest airport, heliport or seaplane base (depending on the type parameter) to those coordinates.

Examples

var info = airportinfo();
print("Nearest airport: ", info.name, " (", info.id, ")"); # prints the name and ICAO code of the nearest airport
var info = airportinfo("heliport");
print("Elevation of the nearest heliport: ", math.round(info.elevation * M2FT), " ft"); # prints the elevation and name of the nearest heliport
var info = airportinfo("KSQL");
print("-- Runways of ", info.name, " (", info.id, "): --");
foreach(var rwy; keys(info.runways)) {
    print(rwy); # prints the runways of KSQL
}
var info = airportinfo(37.81909385, -122.4722484);
print("Coordinates of the nearest airport: ", info.lat, ", ", info.lon); # print the name and ICAO of the nearest airport to the Golden Gate Bridge
var info = airportinfo(37.81909385, -122.4722484, "seaport");
print("Nearest seaplane base: ", info.name, " (", info.id, ")"); # print the name and ID of the nearest seaplane base to the Golden Gate Bridge

This example prints the all information from an airportinfo() call.

var info = airportinfo("KSFO");
print(info.name);
print(info.id);
print(info.lat);
print(info.lon);
print(info.has_metar);
print(info.elevation);
foreach(var rwy; keys(info.runways)){
    print("-- ", rwy, " --");
    print(info.runways[rwy].lat);
    print(info.runways[rwy].lon);
    print(info.runways[rwy].length);
    print(info.runways[rwy].width);
    print(info.runways[rwy].heading);
    print(info.runways[rwy].stopway);
    print(info.runways[rwy].threshold);
}

airwaysRoute()

airwaysRoute(start, end[, type]);

Source

This function returns a vector containing waypoints between two given waypoints. The returned waypoints are ghosts, but can be accessed in the same way as a Nasal hash. See Nasal Flightplan for more information.

start
Start waypoint, in the form of a waypoint ghost, such as that provided by flightplan() .
end
Same as above.
type
Instructs the function to compute a high level route (when set to "highlevel"), or a low level route (when set to "lowlevel"). Defaults to "highlevel."

Examples

In the route manager dialog, add two waypoints to the flightplan, ideally ones that are far apart (tip: use the Map for this). Then run this code in your Nasal Console.

var fp = flightplan();
var start = fp.getWP(0);
var end = fp.getWP(fp.getPlanSize() - 1);
var rt = airwaysRoute(start, end);
foreach(var wp; rt){
    print(wp.wp_name); # print the waypoints in the computed route
}

Exactly the same as above, but computes a low level path.

var fp = flightplan();
var start = fp.getWP(0);
var end = fp.getWP(fp.getPlanSize() - 1);
var rt = airwaysRoute(start, end, "lowlevel");
foreach(var wp; rt){
    print(wp.wp_name); # print the waypoints in the computed route
}

airway()

airway(ident [, pos]);

Source

This function returns a ghost containing an airway of a specified id.

ident
a Positioned ghost (leg, navaid, airport) and so on, passed to the search function.
pos

assert()

assert(condition[, message]);

Source — Version added: FG 3.2 (commit)

Returns either true if the condition evaluates as true, or aborts with a die() call, which can be customised.

condition
Condition to evaluate.
message
Optional message that will be used in any die() call. Defaults to "assertion failed!"

Examples

var a = 1;
var b = 2;
print(assert(a < b)); # prints "1" (true)
var a = 1;
var b = 2;
assert(a > b, 'a is not greater than b'); # aborts with a custom error message

carttogeod()

carttogeod(x, y, z);

Source

Converts Earth-centered, Earth-fixed This is a link to a Wikipedia article coordinates (x, y and z) to geodetic coordinates This is a link to a Wikipedia article (latitude, longitude, and altitude). A vector is returned containing latitude and longitude, both in degrees, and altitude, which is returned in metres above the equatorial radius of Earth as defined by the WGS 84 This is a link to a Wikipedia article (6,378,137 metres).[3]

x
Mandatory x-axis value, in metres.
y
Mandatory y-axis value, in metres.
z
Mandatory z-axis value, in metres.

Example

var (lat, lon, alt) = carttogeod(6378137, 0, 0); # point is the intersection of the prime meridian and equator.
print("Latitude: ", lat); # prints lat, lon and alt, which are all zero, see above
print("Longitude: ", lon);
print("Altitude: ", alt);

cmdarg()

_cmdarg()
cmdarg();

Part 1 | Part 2

cmdarg() returns the property root of certain types of XML files. These could be nodes in the Property Tree, or temporary and/or non-public nodes outside the Property tree.

It is used by Nasal scripts embedded in XML files. It returns a props.Node object (see fgdata/Nasal/props.nas), and you can use all of its methods on the returned value. cmdarg() should only be used in four types/places of XML files:

  • Bindings: This is needed so that the value of a joystick's axis can be accessed internally.
  • Dialogs: This will return the root of the dialog in the Property Tree. This is useful for dialogs that are created/modified procedurally (e.g. for populating/changing widgets while loading the dialog).
  • Embedded Canvases: The Nasal code behind Canvas windows embedded in PUI dialogs can use it to accessing the root directory of their Canvas.
  • Animation XML files: If the animation XML file is used in an AI/MP model, cmdarg() will return the root of the AI model in the /ai/models/ directory. Examples: /ai/models/aircraft[3]/, /ai/models/multiplayer[1]/

You should not use cmdarg() in places other than those stated above. Although it won't cause an error, it will return the value of the last legitimate cmdarg() call.

Also, you should not delay cmdarg() using maketimer() , settimer() or setlistener() , because it will return an unrelated property.

Example

This example demonstrates the usage of cmdarg() in a binding. Save the below XML snippet as $FG_ROOT/gui/dialogs/cmdarg-demo.xml. Then run the Nasal snippet below in your Nasal Console. Upon clicking Close, a message will be printed sowing the root of the binding in the Property Tree.

<?xml version="1.0" encoding="UTF-8"?>

<PropertyList>

<name>cmdarg-demo</name>
<layout>vbox</layout>

<text>
  <label>Click "Close" to activate the demonstration (a message in the console).</label>
</text>

<button>
  <legend>Close</legend>
  <binding>
    <command>nasal</command>
    <script>print("Button binding root: '" ~ cmdarg().getPath() ~ "'");</script>
  </binding>
  <binding>
    <command>dialog-close</command>
  </binding>
</button>

</PropertyList>
fgcommand("dialog-show", {"dialog-name": "cmdarg-demo"});

This example demonstrates the usage of cmdarg() in Nasal code within dialogs. Open $FG_ROOT/gui/dialogs/cmdarg-demo.xml from the previous example, copy & paste the code below, and save it. Then run the same Nasal snippet as the previous example in your Nasal Console. If you click Click me!, the button's label will change to "I've been changed!"

<?xml version="1.0" encoding="UTF-8"?>

<PropertyList>

<name>cmdarg-demo</name>
<layout>vbox</layout>

<text>
  <label>Click "Click me!" to activate the demonstration (the button's label will change).</label>
</text>

<button>
  <legend>Click me!</legend>
  <binding>
    <command>nasal</command>
    <script>change_label();</script>
  </binding>
</button>

<button>
  <legend>Close</legend>
  <binding>
    <command>dialog-close</command>
  </binding>
</button>

<nasal>
  <open><![CDATA[
    var dlg_root = cmdarg();
    var dlg_name = {"dialog-name": "cmdarg-demo"};
    var change_label = func {
        dlg_root.getNode("button[0]/legend").setValue("I've been changed!");
        fgcommand("dialog-close", dlg_name);
        fgcommand("dialog-show", dlg_name);
    }
  ]]></open>
</nasal>

</PropertyList>

For an example of cmdarg() used with Canvas, please see Howto:Adding a canvas to a GUI dialog.

courseAndDistance()

courseAndDistance(to);
courseAndDistance(from, to);

Source

Returns a vector containing the course from one point to another and the distance between them in nautical miles. The course is the initial bearing (see here), and is in the range 0–360. Both arguments can be one of:

  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object with geodetic coordinates (cartesian coordinates will not be accepted)
from
Optional parameter defining the from where the function should calculate its results. If the function is given one argument (to), the aircraft's current position will be used. As well as the argument types as defined above, this argument can be two numbers separated with a comma, as if the function is taking three arguments. See example 5 below.
to
Like the first parameter, but defines the second point.

Examples

This example demonstrates the usage of the function with the airport ghost type.

var from = airportinfo("KSFO");
var to = airportinfo("KSQL");
var (course, dist) = courseAndDistance(from, to);
print(course); # prints course from KSFO to KSQL
print(dist); # prints distance in nm from KSFO to KSQL

This example demonstrates the usage of the function with hashes containing lat and lon.

var from = {lat: 0, lon: 0};
var to = {lat: 1, lon: 1};
var (course, dist) = courseAndDistance(from, to);
print(course);
print(dist);

This example demonstrates usage of a geo.Coord object.

var from = geo.Coord.new().set_latlon(0, 0);
var to = geo.Coord.new().set_latlon(1, 1);
var (course, dist) = courseAndDistance(from, to);
print(course);
print(dist);

This example demonstrates usage of differing parameter types.

var from = airportinfo("KSFO");
var to = geo.Coord.new().set_latlon(0, 0);
var (course, dist) = courseAndDistance(from, to);
print(course);
print(dist);

The same as above, but the other way round.

var to = {lat: 1, lon: 1};
var (course, dist) = courseAndDistance(0, 0, to);
print(course);
print(dist);

Usage of just one parameter.

var dest = airportinfo("KSQL");
var (course, dist) = courseAndDistance(dest);
print("Turn to heading ", math.round(course), ". You have ", sprintf("%.2f", dist), " nm to go");

createFlightplan()

createFlightplan(path);

Source

Creates an empty flightplan object. It accepts one argument, path passed an absolute path to a .fgfp / .gpx file, it will populate the flightplan with waypoints from the file.

path
Optional parameter defining the file from which a flightplan will be populated.

Example

var path = getprop("/sim/fg-home") ~ "/Export/test.fgfp";
var flightplan = createFlightplan(path);
debug.dump(flightplan);

createDiscontinuity()

createDiscontinuity();

Source — Version added: FG 2016.1 (commit)

Returns a waypoint ghost object. A route discontinuity is inserted by an FMS when it is unsure how to connect two waypoints.

createViaTo()

createViaTo(airway, waypoint);

Source — Version added: FG 2016.1 (commit)

Returns a waypoint ghost object. It represents a route "via airway to waypoint".

airway
The name of an airway.
waypoint
Must be in the airway and one of:
  • The name of a waypoint.
  • An airport, navaid, runway, or fix ghost object.

createWP()

createWP(pos, name[, flag]);

Source

Creates a new waypoint ghost object.

pos
Dictates the position of the new waypoint. It can be one of the following:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. See example 4 below.
name
String that will become the name of the new waypoint.
flag
Optional string that will tell FlightGear what type of waypoint it is. Must be one of "sid," "star," "approach," "missed," or "pseudo."

Examples

Creates a waypoint directly in front and 1 km away and appends it to the flight plan.

var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP(pos, "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP({lat: pos.lat(), lon: pos.lon()}, "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
var apt = airportinfo();
var wp = createWP(apt, "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP(pos.lat(), pos.lon(), "NEWWP");
var fp = flightplan();
fp.appendWP(wp);

Creates a new waypoint and adds it to the flight plan. Waypoints of the type "pseudo" are then removed from the flight plan, including the new waypoint. The print() statements show this.

var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP(pos, "NEWWP", "pseudo");
var fp = flightplan();
fp.appendWP(wp);
print(fp.getPlanSize());
fp.clearWPType("pseudo");
print(fp.getPlanSize());

createWPFrom()

createWPFrom(object[, flag]);

Source

Creates a new waypoint object from another object.

object
A ghost object. Must be a ghost type that is one of "airport," "navaid," "runway," or "fix."
flag
Optional string that will tell FlightGear what type of waypoint it is. Must be one of "sid," "star," "approach," "missed," or "pseudo."

Examples

Creates a new waypoint and appends it to the flight plan.

var apt = airportinfo("KSFO");
var wp = createWPFrom(apt);
var fp = flightplan();
fp.appendWP(wp);

Creates a new waypoint and appends it to the flight plan. This way point is then removed; the print() statements prove this.

var apt = airportinfo("KSFO");
var wp = createWPFrom(apt, "pseudo");
print(wp.wp_name);
var fp = flightplan();
fp.appendWP(wp);
print(fp.getPlanSize());
fp.clearWPType("pseudo");
print(fp.getPlanSize());

defined()

defined(symbol);

Source

Returns 1 (true) or 0 (false) depending on whether a variable exists.

symbol
A string that will be what the function searches for.

Example

var number = 12;
var check_exist = func {
    print("Variable 'number' ", defined("number") == 1 ? "exists" : "does not exist"); # 'number' does exist
    print("Variable 'number2' ", defined("number2") == 1 ? "exists" : "does not exist"); # 'number2' does not exist
}
check_exist();

directory()

directory(path);

Source

Returns a vector containing a list of the folders and files in a given file path or nil if the path doesn't exist. Hidden folders and files are not added to the vector.

Note The first two elements of the vector will be '.' and '..'. These are for navigating back up the file tree, but have no use in Nasal. They can be safely removed from the vector.

path
Absolute file path.

Example

Gets the folders and files in $FG_ROOT, and then removes the extra first two elements (see note above).

var dir = directory(getprop("/sim/fg-root")); # get directory
dir = subvec(dir, 2); # strips off the first two elements
debug.dump(dir); # dump the vector

fgcommand()

fgcommand(cmd[, args]);

Part 1 | Part 2

Runs an fgcommand. See also $FG_ROOT/Docs/README.commands and Bindings for more information. See flightgear/src/Main/fg_commands.cxx (line 1425) for the full list of fgcommands. Note that fgcommands generated by addcommand() can also be run using this function. Also, the full list of fgcommands depends on the version of FlightGear you have. Returns 1 (true) if the fgcommand succeeded or 0 (false) if it failed.

cmd
String that is the name of the command that is to be run.
args
If the fgcommand takes arguments, they are inputted using this argument. Can either be a props.Node object, or a hash (see examples below).

Examples

fgcommand("null"); # does nothing
var args = props.Node.new({'script': 'print("Running fgcommand");'});
if (fgcommand("nasal", args)) { # prints "Running fgcommand" and then one of these print statements
    print("Fgcommand succeeded");
} else {
    print("Fgcommand encountered a problem");
}
var args = { 'dialog-name': 'about' };
fgcommand("dialog-show", args); # shows the 'about' dialog

findAirportsByICAO()

findAirportsByICAO(search[, type]);

Source

Returns a vector containing airport ghost objects which are (by default) airports whose ICAO code matches the search string. The results are sorted by range from closest to furthest.

search
Search string for the function. Can either be a partial or a full ICAO code.
Caution The more matches there are for the given code, the longer the function will take. Passing just one character (e.g., "K"), might make FlightGear hang for a certain amount of time.
type
This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of "airport," "heliport," or "seaport."

Examples

var apts = findAirportsByICAO("KSF"); # finds all airports matching "KSF"
foreach(var apt; apts){
    print(apt.name, " (", apt.id, ")"); # prints them
}
var apts = findAirportsByICAO("SP0", "seaport"); # finds all seaplane bases matching "SP0"
foreach(var apt; apts){
    print(apt.name, " (", apt.id, ")"); # prints them
}
var apt = findAirportsByICAO("XBET"); # one way to check if an airport does exist"
if (size(apt) == 0) {
    print("Airport does not exist"); # this one will be printed
} else {
    print("Airport does exist");
}

findAirportsWithinRange()

findAirportsWithinRange([pos, ]range[, type]);

Source

Returns a vector of airport ghost object which are (by default) airports that are within a given range of a given position, or the aircraft's current position. The results are sorted by range from closest to furthest.

pos
Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findAirportsWithinRange(lat, lon, range, type);.
range
Mandatory number giving the range in nautical miles within which to search for airports/heliports/seaplane bases.only airports are searched for.
type
This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of "airport," "heliport," or "seaport."

Examples

Searches for airports within 10 nm of KSFO.

var pos = airportinfo("KSFO");
var apts = findAirportsWithinRange(pos, 10);
foreach(var apt; apts){
    print(apt.name, " (", apt.id, ")");
}

Searches for seaplane bases within 15 nm of KSFO.

var pos = airportinfo("KSFO");
var apts = findAirportsWithinRange(pos, 15, "seaport");
foreach(var apt; apts){
    print(apt.name, " (", apt.id, ")");
}

Searches for airports within 10 nm of your current position.

var apts = findAirportsWithinRange(10);
foreach(var apt; apts){
    print(apt.name, " (", apt.id, ")");
}

findCommByFrequencyMHz()

findCommByFrequencyMHz([pos, ]freq[, type]);

source

Returns a comm ghost object for a station matching a given frequency. If there is more than one station with that frequency, the nearest station is returned.

pos

Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findCommByFrequencyMHz(lat, lon, freq, type);.
freq
Frequency, in megahertz, of the station to search for.
type
This will narrow the search to station of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 160)

Example

var com = findCommByFrequencyMHz(123.6);
print("ID: ", com.id); # prints info about the comm station
print("Name: ", com.name);
print("Latitude: ", com.lat);
print("Longitude: ", com.lon);
print("Type: ", com.type);
print("Frequency: ", sprintf("%.3f", com.frequency), " Mhz");

findFixesByID()

findFixesByID([pos, ]id);

Source

Returns a vector containing fix ghost objects matching a given ID, sorted by range from a certain position.

Note Fixes are (usually) also known as waypoints.

pos
Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findFixesByID(lat, lon, id);.
id
Full or partial ID of the fix to search for.
Note Inputting a partial ID does not work correctly (see here). It is best to just input a full ID.

Examples

var fixes = findFixesByID("POGIC");
foreach(var fix; fixes){
    print(fix.id, " - lat: ", fix.lat, " | lon: ", fix.lon); # prints information about POGIC
}
var fix = findFixesByID("ZUNAP");
fix = fix[0];
var (course, dist) = courseAndDistance(fix);
print("Turn to heading ", math.round(course), ". You have ", sprintf("%.2f", dist), " nm to go to reach ", fixes[0].id);

findNavaidByFrequencyMHz()

findNavaidByFrequencyMHz([pos, ]freq[, type]);

Source

Returns a navaid ghost object for a navaid matching a given frequency. If there is more than one navaid with that frequency, the nearest station is returned.

pos
Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findNavaidByFrequencyMHz(lat, lon, freq, type);.
freq
Frequency, in megahertz, of the navaid to search for.
type
This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).

Example

var navaid = findNavaidByFrequencyMHz(109.55);
print("ID: ", navaid.id); # prints info about the navaid
print("Name: ", navaid.name);
print("Latitude: ", navaid.lat);
print("Longitude: ", navaid.lon);
print("Elevation (AMSL): ", navaid.elevation, " m");
print("Type: ", navaid.type);
print("Frequency: ", sprintf("%.3f", navaid.frequency / 100), " Mhz");
print("Range: ", navaid.range_nm, " nm");
if(navaid.course) print("Course: ", navaid.course);

findNavaidsByFrequencyMHz()

findNavaidsByFrequencyMHz([pos, ]freq[, type]);

Source

Returns a vector conatining navaid ghost objects for navaids that match a given frequency, sorted from nearest to furthest.

pos
Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findNavaidsByFrequencyMHz(lat, lon, freq, type);.
freq
Frequency, in megahertz, of the navaid to search for.
type
This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).

Example

var navaids = findNavaidsByFrequencyMHz(109.55);
foreach(var navaid; navaids){
    print("--");
    print("ID: ", navaid.id); # prints info about the navaid
    print("Name: ", navaid.name);
    print("Latitude: ", navaid.lat);
    print("Longitude: ", navaid.lon);
    print("Elevation (AMSL): ", navaid.elevation, " m");
    print("Type: ", navaid.type);
    print("Frequency: ", sprintf("%.3f", navaid.frequency / 100), " Mhz");
    print("Range: ", navaid.range_nm, " nm");
    if(navaid.course) print("Course: ", navaid.course);
    print("--");
}

findNavaidsByID()

findNavaidsByID([pos, ]id[, type]);

Source

Returns a vector containing navaid ghost objects matching a given ID, sorted by range from a certain position.

pos
Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findNavaidsByID(lat, lon, id, type);.
id
Full or partial ID of the fix to search for.
Note Inputting a partial ID does not work correctly (see here). It is best to just input a full ID.
type
This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).

Example

var navaid = findNavaidsByID("MXW");
navaid = navaid[0];
print("ID: ", navaid.id); # prints info about 'MXW' (a VOR station)
print("Name: ", navaid.name);
print("Latitude: ", navaid.lat);
print("Longitude: ", navaid.lon);
print("Elevation (AMSL): ", navaid.elevation, " m");
print("Type: ", navaid.type);
print("Frequency: ", sprintf("%.3f", navaid.frequency / 1000), " Mhz");
print("Range: ", navaid.range_nm, " nm");

findNavaidsWithinRange()

findNavaidsWithinRange([pos, ]range[, type]);

Source

Returns a vector of navaid ghost objects which are within a given range of a given position (by default the aircraft's current position). The results are sorted from closest to furthest.

pos
Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost type
  • A hash with lat and lon members
  • A geo.Coord object
  • Two numbers separated by a comma, as if the function is taking three arguments. Example: findNavaidsWithinRange(lat, lon, range, type);.
range
Mandatory number giving the range in nautical miles within which to search for navaids.
type
This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).

Examples

Searches for navaids within 10 nm of KSFO.

var pos = airportinfo("KSFO");
var navs = findNavaidsWithinRange(pos, 10);
foreach(var nav; navs){
    print(nav.name, " (ID: ", nav.id, ")");
}

Searches for navaids within 10 nm of your current position.

var navs = findNavaidsWithinRange(10);
foreach(var nav; navs){
    print(nav.name, " (ID: ", nav.id, ")");
}

finddata()

finddata(path);

Source

Takes a relative path and tries to return an absolute one. It works by appending the relative path to some paths and testing to see if they exist. As of FlightGear v3.7, these paths are the TerraSync directory (tested first) and $FG_ROOT.

path
A relative path as a string.

Examples

var path = finddata("Aircraft/Generic");
print(path); # prints the absolute path to $FG_ROOT/Aircraft/Generic
var path = finddata("Airports");
print(path); # prints the absolute path to <TerraSync dir>/Airports
var path = finddata("preferences.xml");
print(path); # prints the absolute path to $FG_ROOT/preferences.xml

flightplan()

flightplan([path]);

Source

Returns a flight plan object, either one for the current flight plan, or one loaded from a given path.

path
Optional path to flight plan XML file.

Examples

Gets the active flight plan and gets the ID of the current waypoint. Note that this example requires a flight plan to be set in the Route Manager first.

var fp = flightplan();
print(fp.getWP(fp.current).id);

Creates a new flight plan from an XML file and prints the IDs of the waypoints. Note that this example requires a flight plan to have been created and saved as $FG_HOME/fp-demo.xml.

var path = getprop('/sim/fg-home') ~ '/fp-demo.xml';
var fp = flightplan(path);
for(var i = 0; i < fp.getPlanSize(); i += 1){
    print(fp.getWP(i).id);
}

geodinfo()

geodinfo(lat, lon[, max_alt]);

Source

Returns a vector containing two entries or nil if no information could be obtained because the terrain tile wasn't loaded. The first entry in the vector is the elevation (in meters) for the given point, and the second is a hash with information about the assigned material (as defined in $FG_ROOT/Materials), or nil if there was no material information available (for example, because there is an untextured building at that location). The structure of the hash is as follows (see also $FG_ROOT/Docs/README.materials):

  • light_coverage: The coverage of a single point of light in m2.
  • bumpiness: Normalized bumpiness factor for the material.
  • load_resistance: The amount of pressure in N/m2 the material can withstand without deformation.
  • solid: 1 (true) or false (0) depending on whether the material is solid or not.
  • names: Vector of scenery types (usually generated by TerraGear) that will use this material.
  • friction_factor: Normalized friction factor of the material.
  • rolling_friction: The rolling friction coefficient of the material.

Note that this function is a very CPU-intensive operation, particularly in FlightGear v2.4 and earlier. It is advised to use this function as little as possible.

lat
Latitude, inputted as a number.
lon
Longitude, inputted as a number.
max_alt
The altitude, in metres, from which the function will begin searching for the height of the terrain. Defaults to 10,000 metres. If the terrain is higher than this argument specifies, nil will be returned.

Examples

Dumps information about ground underneath the aircraft.

var pos = geo.aircraft_position();
var info = geodinfo(pos.lat(), pos.lon());
debug.dump(info);

Prints whether the ground underneath the aircraft is solid or is water.

var pos = geo.aircraft_position();
var info = geodinfo(pos.lat(), pos.lon());
if (info != nil and info[1] != nil) {
    print("The ground underneath the aircraft is ", info[1].solid == 1 ? "solid." : "water.");
}

geodtocart()

geodtocart(lat, lon, alt);

Source

Converts geodetic coordinates This is a link to a Wikipedia article (latitude, longitude, and altitude) to Earth-centered, Earth-fixed This is a link to a Wikipedia article coordinates (x, y and z). A vector is returned containing x, y, and z in metres. The equatorial radius of earth used is that defined by the WGS 84 This is a link to a Wikipedia article (6,378,137 metres). All argument are mandatory.

lat
Latitude, in degrees.
lon
Longitude, in degrees.
alt
Altitude, in metres.

Example

var (x, y, z) = geodtocart(0, 0, 0); # point is the intersection of the prime meridian and equator.
print("x: ", x); # prints "x: 6378137"
print("y: ", y); # prints "y: 0"
print("z: ", z); # prints "y: 0"

get_cart_ground_intersection()

Introduced in 2017.2.1, see Terrain Detection.

getprop()

getprop(path[, path[, ...]]);

Source

Returns the value of a node in the Property Tree or nil if the node does not exist or the value is not a number (NaN).

path
There needs to be at least one argument, but there is no limit to the maximum amount of arguments that can be given. The arguments will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there is also support (added by FlightGear commit 34ed79) for numeric arguments as indices. See example 2 below.

Examples

print("You have FlightGear v", getprop("/sim/version/flightgear")); # prints FlightGear version

Note that the example below will only work in FlightGear 3.2 and above.

for(var i = 0; i < 8; i += 1){
    print("View #", i + 1, " is named ", getprop("/sim/view", i, "name"));
}

Same as above, but is supported by all versions of FlightGear.

for(var i = 0; i < 8; i += 1){
    print("View #", i + 1, " is named ", getprop("/sim/view[" ~ i ~ "]/name"));
}

See also

Note  If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object:

To get a Node rather than its value, use props.globals.getNode() - see Nasal_library/props.

greatCircleMove()

greatCircleMove([pos, ]course, dist);

Source

Calculates a new set of geodetic coordinates using inputs of course and distance, either from the aircraft's current position (by default) or from another set of coordinates. Returns a hash containing two members, lat and lon (latitude and longitude respectively).

pos
Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost object.
  • A hash with lat and lon members
  • A geo.Coord object
  • A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma: greatCircleMove(lat,lon, ...).
course
Course to new set of coordinates, in degrees (in the range 0–360).
dist
Distance in nautical miles to the new set of coordinates.

Examples

var pos = greatCircleMove(0,0, 0, 1);
debug.dump(pos); # print hash with coordinates
var fix = findFixesByID("POGIC");
fix = fix[0];
var pos = greatCircleMove(fix, 45, 10);
debug.dump(pos); # print hash with coordinates

interpolate()

_interpolate()
interpolate(prop, value1, time1[, value2, time2[, ...]]);

Part 1 | Part 2

Linearly interpolates a node in the property tree to a given value in a specified time. The value/time pairs will be run one after the other in the order that they are passed to the function. Note that the interpolation will continue even when the simulation is paused.

prop
String or props.Node object that indicates a node in the property tree to be used.
valuen
Target value to change the property to in the set amount of time. This should be a number.
timen
Time in seconds, that will be taken for the interpolation.

Examples

Paste the code below into the Nasal Console and execute. Then, open the Property Browser and look for the property. Finally, run the code again, and watch the value of the property change.

setprop("/test", 0); # (re-)set property
interpolate("/test",
    50, 5, # interpolate to 50 in 5 seconds
    10, 2, # interpolate to 10 in 2 seconds
    0, 5); # interpolate to 0 in 5 seconds
# Apply the left brake at 20% per second
var prop = "controls/gear/brake-left";
var dist = 1 - getprop(prop);
if (dist == 1) {
    interpolate(prop, 1, dist / 0.2);
}

isa()

isa(object, class);

Source

Checks if an object is an instance of, or inherits from, a second object (or class), returning 1 (true) if it is and 0 (false) if otherwise.

object
Object to check.
class
Class/object to check that object inherits from or is an instance of.

Examples

var coord = geo.Coord.new();
if(isa(coord, geo.Coord)){
    print("Variable 'coord' is an instance of class 'geo.Coord'"); # this one will be printed
} else {
    print("Variable 'coord' is not an instance of class 'geo.Coord'");
}
var coord = geo.Coord.new();
if(isa(coord, props.Node)){
    print("Variable 'coord' is an instance of class 'props.Node'");
} else {
    print("Variable 'coord' is not an instance of class 'props.Node'"); # this one will be printed
}

The example below demonstrates checking of inheritance.

var Const = {
    constant: 2,
    getConst: func {
        return me.constant;
    }
};

var Add = {
    new: func {
        return { parents: [Add, Const] };
    },

    addToConst: func(a){
        return a * me.getConst();
    }
};

var m = Add.new();
print(m.addToConst(4));

if(isa(m, Add)) print("Variable 'm' is an instance of class 'Add'"); # will be printed
if(isa(m, Const)) print("Variable 'm' is an instance of class 'Const'"); # will also be printed

logprint()

logprint(priority[, msg[, msg[, ...]]]);

Source

Concatenates a message and logs it with a given priority level. Unlike print() and printlog() , message outputted by this function will be logged in your fgfs.log file as coming from the Nasal file itself rather than from flightgear/src/Scripting/NasalSys.cxx.

priority
Number specifying the priority level of the outputted message:
Number Debug type
1 Bulk
2 Debug
3 Info
4 Warn
5 Alert
msg
The message. There is no limit to the arguments you give give. They will be concatenated together before logging.

Examples

# logs the value of pi to three decimal places with log level 3
logprint(3, "pi = ", sprintf("%.3f", math.pi));
logprint(5, "Alert! This is an important message!");
Note

The following constants have been added to the development branch of FlightGear ("next") and will be releases with FG 2020.1 so you won't have to remember the numbers anymore:

LOG_BULK, LOG_WARN, LOG_DEBUG, LOG_INFO, LOG_ALERT, DEV_WARN, DEV_ALERT

magvar()

magvar([pos]);

Source

Returns the magnetic variation This is a link to a Wikipedia article at a given set of coordinates. The table below gives the magnetic model used depending on the version of FlightGear.

FlightGear versions Model Reference date
3.6 and above World Magnetic Model This is a link to a Wikipedia article (WMM) 2015 1 January 2015
0.9.11-pre1 to 3.4 WMM 2005 1 January 2005
0.7.3 to 0.9.10 WMM 2000 1 January 2000
pos
Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:
  • An airport, navaid, runway, taxiway, fix, or waypoint ghost object.
  • A hash with lat and lon members
  • A geo.Coord object
  • A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma: magvar(lat,lon).

Example

print(magvar(0, 0)); # prints the magnetic variation at 0, 0

maketimer()

maketimer(interval[, self], function);

Implemented using the TimerObj (doxygen) class.
Part 1 | Part 2 — Version added: FG 2.12 (commit)

Returns a timer object containing the following methods and members:

  • start(): Starts the timer.
  • stop(): Stops the timer.
  • restart(interval): Restarts the timer with the given interval.
  • singleShot: Bool showing whether the timer is only to be run once, or continuously until told to stop. Can be both set and read from (see examples).
  • isRunning: Read-only bool telling whether the timer is currently running.
  • simulatedTime: (FG 2017.1+; commit) Bool telling whether the timer is using simulated time (which accounts for pause, etc.). Defaults to false (use real time). Can be both read and set. This cannot be changed while the timer is running.

Unlike settimer() , which it replaces, maketimer() provides more control over the timer. In addition, it can help reduce memory usage.

interval
Interval in seconds for the timer.
self
Optional parameter specifying what any me references in the function being called will refer to.
function
Function to be called at the given interval.

Examples

var timer = maketimer(1, func(){
    print("Hello, World!"); # print "Hello, World!" once every second (call timer.stop() to stop it)
});
timer.start();
var timer = maketimer(1, math, func(){
    print(me.math); # 'me' reference is the 'math' namespace
});
timer.singleShot = 1; # timer will only be run once
timer.start();
var timer = maketimer(1, func(){
    print("Hello, World!"); # print "Hello, World!" once every second (call timer.stop() to stop it)
});
timer.start();
print(timer.isRunning); # prints 1

In the example below, "Hello, World!" will be printed after one second the first time, and after two seconds thereafter.

var update = func(){
    print("Hello, World!");
    timer.restart(2); # restarts the timer with a two second interval
}

var timer = maketimer(1, update);
timer.singleShot = 1;
timer.start();

maketimestamp()

maketimestamp()

Implemented using the TimeStampObj (doxygen) class.
Part 1 | Part 2 — Version added: FG 2019.2 (commit)

Returns a time stamp object to allow high resolution timing of Nasal operations. When created the timer will automatically be stamped. The object has the following methods:

  • stamp(): Resets the timing operation. Call this first.
  • elapsedMSec(): returns number of milliseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.
  • elapsedUSec(): returns number of microseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.

Example

In the example below the number of milliseconds elapsed will be printed.

var timestamp = maketimestamp();
timestamp.stamp();
print(timestamp.elapsedMSec(), "ms elapsed");
print(timestamp.elapsedMSec(), "ms elapsed");

md5()

md5(string);

Source — Version added: FG 3.2 (commit)

Returns a the MD5 This is a link to a Wikipedia article hash (as a string) of the inputted string.

string
String the generate the hash of. Mandatory.

Example

The below code should output 65a8e27d8879283831b664bd8b7f0ad4.

print(md5("Hello, World!"));

navinfo()

navinfo(lat, lon, type, id);

Source

Returns vector navaid ghost objects matching the given type and id or nil on error.

lat and lon
If given, the returned navaids will be put into order of ascending distance from the location.
type
Narrows the search to the given type. Must be one of "any," "fix," "vor," "ndb," "ils," "dme," or "tacan." Defaults to the equivalent of "any."
id
ID to search for. Note that, although all the parameters are technically optional, this parameter must be given, otherwise an empty vector will be returned.

Examples

navinfo("vor"); # returns all VORs
navinfo("HAM"); # return all navaids whose names start with "HAM"
navinfo("vor", "HAM"); # return all VORs whose names start with "HAM"
navinfo(34,48,"vor","HAM"); # return all VORs whose names start with "HAM" and sorted by distance relative to 34°, 48°

parse_markdown()

parse_markdown(markdown);

Part 1 | Part 2 — Version added: FG 3.2

Parses a string containing Markdown This is a link to a Wikipedia article and returns the result as a string. As of FlightGear 2016.1, it is just a simple parser, and does the following:

  • It strips whitespace from the beginning of the string.
  • It supports paragraphs and line breaks.
  • It collapses whitespace.
  • It converts unordered lists to use a bullet character (•). Note that the bullet character is implemented in hexadecimal UTF-8 character bytes (E2 80 A2), as so may not work properly when the being displayed in an encoding other than UTF-8.
markdown
String containing Markdown to be parsed.

Examples
Save the below code as $FG_ROOT/gui/dialogs/test.xml, then run the Nasal code below it to open the dialog. To change the markdown to be parsed, simply change the code in the highlighted section, save it, and reload the GUI (Debug > Reload GUI).

<?xml version="1.0" encoding="UTF-8"?>

<PropertyList>

<name>test</name>
<layout>vbox</layout>

<group>
    <layout>hbox</layout>
    
    <empty>
        <stretch>true</stretch>
    </empty>
    
    <text>
        <label>parse_markdown() test dialog</label>
    </text>
    
    <empty>
        <stretch>true</stretch>
    </empty>

    <button>
        <legend></legend>
        <pref-width>16</pref-width>
        <pref-height>16</pref-height>
        <binding>
            <command>dialog-close</command>
        </binding>
    </button>

</group>

<canvas>
    <name>Canvas plot</name>
    <stretch>true</stretch>
    <pref-width>400</pref-width>
    <pref-height>300</pref-height>
    <nasal>
        <load><![CDATA[
var text = 'Items:
* apples
* oranges
* pears

Some text.
Some more items:
* apples
* oranges
* pears';

var parsed = parse_markdown(text);

var root_canvas = canvas.get(cmdarg());
root_canvas.setColorBackground(255, 255, 255);
var root = root_canvas.createGroup();

var text_dis = root.createChild("text")
    .setText(parsed)
    .setTranslation(5, 5)
    .setFont("LiberationFonts\LiberationSans-Regular.ttf")
    .setFontSize(15)
    .setColor(0, 0, 0)
    .setDrawMode(canvas.Text.TEXT)
    .setAlignment("left-top");
        ]]></load>
    </nasal>
</canvas>

</PropertyList>
fgcommand("dialog-show", {"dialog-name": "test"});

The example below parses Markdown and outputs it in a HTML document. The parsed text is placed in <pre></pre> tags. To change the Markdown to be parsed, simply edit the variable markdown at the top of the code.

var markdown = 'Items:
* apples
* oranges
* pears

Some text.
Some more items:
* apples
* oranges
* pears';

var parsed = parse_markdown(markdown);

debug.dump(parsed);

var path = string.normpath(getprop("/sim/fg-home") ~ '/Export/parse_markdown()-test.html');

var file = io.open(path, "w");

var html = "&lt;!DOCTYPE html&gt;\n\n&lt;html&gt;\n\n&lt;head&gt;\n\t&lt;meta charset=\"UTF-8\"&gt;\n\t&lt;title&gt;parse_markdown() test generated by Nasal&lt;/title&gt;\n&lt;/head&gt;\n\n&lt;body&gt;\n\t&lt;pre&gt;" ~ parsed ~ "&lt;/pre&gt;\n&lt;/body&gt;\n\n&lt;/html&gt;";

io.write(file, html);
io.close(file);
print("Done, file ready for viewing (" ~ path ~ ")");

parsexml()

parsexml(path[, start[, end[, data[, pro_ins]]]]);

Source

This function is an interface into the built-in Expat XML parser. The absolute path to the file is returned as string, or nil is returned on error.

path
Mandatory absolute path to the XML file to be parsed.
start
Optional callback function that will be called for every starting tag. The function should take two argument: the tag name and a hash containing attributes.
end
Optional callback function that will be called for every ending tag. The function should take one argument: the tag name.
data
Optional callback function that will be called for every piece of data within a set of tags. The function should take one argument: the data as a string.
pro_ins
Optional callback function that will be called for every processing instruction This is a link to a Wikipedia article. The function should take two argument: the target and the data string.

Example
Save the below XML code in $FG_HOME/Export/demo.xml. Then, execute the Nasal code below in the Nasal Console. The XML will be parsed and each bit of the code will be printed.

<?xml version="1.0" encoding="UTF-8"?>

<?xml-stylesheet type="text/xsl" href="style.xsl"?>

<foo>
  <blah type="string"><![CDATA[ <sender>John Smith</sender> ]]></blah>
  <blah2 type="string">Orange &amp; lemons</blah2>
</foo>
var start = func(name, attr){
    print("Starting tag: '", name, "'");
    foreach(var a; keys(attr)){
        print("\twith attribute ", a, '="', attr[a], '"');
    }
}

var end = func(name){
    print("Ending tag: '", name, "'");
}

var data = func(data){
    print("Data = '", data, "'");
}

var pro_instr = func(target, data){
    print("Processing instruction: target = '", target, "', data = '", data, "'");
}

parsexml(getprop("/sim/fg-home") ~ '/Export/demo.xml', start, end, data, pro_instr);

print()

Note  As of 07/2020, we are in the process of slowly deprecating and removing Nasal print() (in fgdata) where possible in favor of log #logprint() which takes a priority level.

This is part of the goal that we achieve zero output at log-level at alert, and everything shown at ‘warn; is really a warning, not just information.[4]

print(data[, data[, ...]]);

Source

Concatenates its arguments and then prints it to the terminal and the log. Note that a newline is automatically added.

data
Data to print. Only strings and numbers can be printed; other data types will not be. There many be any number of arguments; they will just be concatenated together.

Examples

print("Just", " a ", "test"); # prints "Just a test"
print("pi = ", math.pi); # prints "pi = 3.141592..."

printf()

printf(format[, arg[, arg, [...]]]);

Source

Creates and prints a formatted string. For a description of its arguments, see sprintf() (it is, in fact, implemented using sprintf()).

Example

printf("In hexadecimal, 100000 = %X", 186A0); # prints "In hexadecimal, 100000 = 186A0"

printlog()

printlog(level, data[, data[, ...]]);

Source

Prints the given message with the given log level. If the log level is higher or equal to /sim/logging/priority, it is printed.

level
Mandatory log level as a string. Must be one of "none," "bulk," "debug," "info," "warn," or "alert." Note that "none" will mean that the message will never be printed.
data
Data to be printed. Only strings and numbers will be printed; others will not be. There may be any number of arguments; they will just be concatenated together.

Examples

printlog("alert", "This is an alert"); # message will be printed
printlog("info", "Just informing you about something"); # message will be printed only if log level is set to "info" or less

rand()

rand();

Source

Returns a random floating point number between 0 (inclusive) and 1 (exclusive). It takes no arguments.

Example

print(rand()); # prints random number

registerFlightPlanDelegate()

registerFlightPlanDelegate(init_func);

Source

Registers a flight plan delegate. See $FG_ROOT/Nasal/route_manager.nas for examples.

init_func
Initialization function which will be called during FlightGear's startup.

removecommand()

removecommand(cmd);

Source

Removes the given fgcommand. Returns nil.

Caution  This will remove any fgcommand, even those implemented in C++, so use with caution!
cmd
String specifying the name of the command to remove.

Example

addcommand("hello", func(){
    print("Hello");
});
fgcommand("hello"); # "Hello" will be printed
removecommand("hello"); # removes it

removelistener()

removelistener(id);

Part 1 | Part 2

Removes and deactivates the given listener and returns the number of listeners left or nil on error.

Note  It is good practice to remove listeners when they are not required anymore. This prevents the listeners reducing FlightGear's run performance.
id
ID of listener as returned by setlistener() .

Example

var ls = setlistener("/sim/test", func(){
    print("Property '/sim/test' has been changed");
});
setprop("/sim/test", "blah"); # trigger listener
var rem = removelistener(ls); # remove listener
print("There are ", rem, " listeners remaining");

resolvepath()

resolvepath(path);

Source

Takes a relative path as a string and uses SimGear's path-resolving framework to return an absolute path as a string. If the path could not be resolved, an empty string is returned. See Resolving Paths for a detailed description of the algorithm. This function can also be used to check if a file exists.

path
Relative path to be completed.

Examples

print(resolvepath("Nasal/globals.nas")); # prints the equivalent of $FG_ROOT/Nasal/globals.nas
print(resolvepath("blah")); # prints nothing; could not be resolved
var file_path = resolvepath("Aircraft/SenecaII/some-file");
if (file_path != ""){
    gui.popupTip("some-file found", 2);
} else {
    gui.popupTip("some-file not found", 2);
}

setlistener()

_setlistener()
setlistener(node, code[, init[, type]]);

Part 1 | Part 2
Listener implemented using the FGNasalListener (doxygen) class.

Creates a listener which will be triggered when the given property is changed (depending on the type). A unique integer ID is returned; this can later be used as the argument to removelistener() .

Note  Listeners are known to be a source of resource leaks. To avoid this, please take measures such as:
  • Using removelistener() when they are not needed any more.
  • Using a single initialization listener.
  • Avoiding tying listeners to properties that are rapidly updated (e.g., many times per frame).
node
Mandatory string or props.Node object pointing to a property in the Property Tree.
code
Mandatory callback function to execute when the listener is triggered. The function can take up to four arguments in the following order:
  • changed: a props.Node object pointing to the changed node.
  • listen: a props.Node object pointing to the listened-to node. Note that this argument maybe different depending on the type.
  • mode: an integer telling how the listener was triggered. 0 means that the value was changed. 1 means that a child property was added. -1 means that a child property was removed.
  • is_child: boolean telling whether changed is a child property of the listened-to node or not. 1 (true) if it is, 0 (false) otherwise.
init
If set to 1 (true), the listener will additionally be triggered when it is created. This argument is optional and defaults to 0 (false).
type
Integer specifying the listener's behavior. 0 means that the listener will only trigger when the property is changed. 1 means that the trigger will always be triggered when the property is written to. 2 will mean that the listener will be triggered even if child properties are modified. This argument is optional and defaults to 1.

Example

var prop = props.globals.initNode("/sim/test", "", "STRING"); # create property
var id = setlistener("/sim/test", func(n){ # create listener
    print("Value: ", n.getValue());
});
setprop("/sim/test", "blah"); # trigger listener
removelistener(id); # remove listener
prop.remove(); # remove property

setprop()

setprop(path[, path[, ...]], value);

Source

Sets the value of a property in the Property Tree. If the property does not exist, it will be created. Returns 1 (true) on success or 0 (false) if there was an error.

Note  If you want to remove a property, you will have to use one of the props helpers:
props.globals.getNode("foo/bar").remove(); # take out the complete node
props.globals.getNode("foo").removeChild("bar"); # take out a certain child node
path
There needs to be at least one path argument, but there is no limit to the maximum amount that can be given. They will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there also is support (added by FlightGear commit 34ed79) for numeric arguments as indices. See example 2 below.
value
Value to write to the given property. Must be either a string or a number.

Examples

setprop("/sim/demo", "This is a demo");

Note that the example below will only work in FlightGear 3.2 and above.

for(var i = 0; i < 3; i += 1){
    setprop("/sim/demo", i, "Demo #" ~ i));
}

Same as above, but is supported by all versions of FlightGear.

for(var i = 0; i < 3; i += 1){
    setprop("/sim/demo[" ~ i ~ "]", "Demo #" ~ i));
}

See also

Note  If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object:

To get a Node rather than its value, use props.globals.getNode() - see Nasal_library/props.

settimer()

settimer(function, delta[, realtime]);

Part 1 | Part 2

Runs the given function a specified amount of seconds after the current time. Returns nil.

Note  Improper use of settimer() may cause resource leaks. It is also highly recommended that the newer maketimer() should be used instead of this function.
function
Mandatory function that will be called. It may be necessary to enclose code in an anonymous function (see example).
delta
Mandatory amount of time in seconds after which the function will be called.
realtime
If 1 (true), "real time" will be used instead of "simulation time." Defaults to 0 (false). Note that if "simulation time" is used, the timer will not run while FlightGear is paused.

Examples

var myFunc = func(){
    print("Hello");
}

settimer(myFunc, 2); # runs myFunc after 2 seconds
var sqr = func(a){
    return a * a;
}

settimer(func(){
    print(sqr(2)); # will print 4 after 2 seconds
}, 2);

srand()

srand();

Source

Makes the pseudorandom number generator (see rand() ) generate a new random seed based on time. Returns 0.

systime()

systime();

Source

Returns the Unix time This is a link to a Wikipedia article (seconds since since 00:00:00 UTC, 1/1/1970) as a floating point number with high resolution. This function is useful for benchmarking purposes (see example 2).

Note  High resolution timers under Windows can produce inaccurate or fixed sub-millisecond results.[5] This is due to the underlying GetSystemTimeAsFileTime() API call, which depends on hardware availability of suitable high resolution timers. See also Acquiring high-resolution time stamps

Examples

print("Unix time: ", systime()); # prints Unix time
var myFunc = func(){
    for(var i = 0; i <= 10; i += 1){
        print("Interation #", i);
    }
}
var t = systime(); # record time
myFunc(); # run function
var t2 = systime(); # record new time
print("myFunc() took ", t2 - t, " seconds"); # print result

thisfunc()

thisfunc();

Source

Returns the function from which this function is called. This allows a function to reliably and safely call itself from within a closure.

Example

var stringify_vec = func(input){
    if (typeof(input) == "scalar"){
        return sprintf("%s", input);
    } elsif (typeof(input) == "vector") {
        if (size(input) == 0) return "[]";
        var this = thisfunc();
        var buffer = "[";
        for(var i = 0; i < size(input); i += 1){
            buffer ~= this(input[i]);
            if (i == size(input) - 1) {
                buffer ~= "]";
            } else {
                buffer ~= ", ";
            }
        }
        return buffer;
    } else {
        die("stringify_vec(): Error! Invalid input. Must be a vector or scalar");
    }
}

var test_vec = ["a", "b", "c", 1, 2, 3];
debug.dump(stringify_vec(test_vec)); # prints "[a, b, c, 1, 2, 3]"
test_vec = [];
debug.dump(stringify_vec(test_vec)); # prints "[]"
test_vec = {};
debug.dump(stringify_vec(test_vec)); # will throw an error

tileIndex()

tileIndex();

Source

Returns the index of the tile at the aircraft's current position as a string. This corresponds to the name of the STG file of the tile. For example, at KSFO, this would be 942050, corresponding to $FG_SCENERY/Terrain/w130n30/w123n3/942050.stg.

Example

print(tileIndex()); # print index

tilePath()

tilePath();

Source

Returns the base path of the tile at the aircraft's current position as a string. For example, at KSFO, this would be w130n30/w123n3, corresponding to $FG_SCENERY/Terrain/w130n30/w123n3.

Example

print(tilePath()); # print path

values()

values(hash);

Source

Returns a vector containing the values of the given hash.

hash
Mandatory hash to get the values of.

Examples

var hash = {
    "a": 1,
    "b": 2,
    "c": 3
};

foreach(var val; values(hash)){
    print(val);
}

The below example does exactly the same thing as the above example, but does not use values():

var hash = {
    "a": 1,
    "b": 2,
    "c": 3
};

foreach(var key; keys(hash)){
    print(hash[key]);
}

Extension functions new in FG 2020.1

The following functions have been added to the nasal core library and will be released with FlightGear version 2020.1. Before the release they are available in the development branch "next".

isfunc()

Returns 1 if type or argument is a function, otherwise 0.

isghost()

Returns 1 if type or argument is a ghost, otherwise 0.

ishash()

Returns 1 if type or argument is a hash, otherwise 0.

isint()

isint(x);

Source

Returns 1 if argument has a numeric value and x == floor(x), e.g. integer.

isnum()

isnum(x);

Source

Returns 1 if typeof(x) is "scalar" and x has a numeric value otherwise 0.

isscalar()

isscalar(x);

Source

Returns 1 if type or argument is a scalar (string or numeric), otherwise (vector, hash, func, ...) it returns 0. This is useful to check if a variable can be converted to string e.g. when useing the string concat operator "~".

Example

var a = "foo"; 
var b=42;
if (isscalar(a) and isscalar(b)) print(a~b);
if (isstr(a)) print("a is a string");
if (isint(b)) print("b is an integer");
# if (isscalar(a))... is equivalent to if (typeof(a) == "scalar")...

isstr()

Returns 1 if type or argument is a string, otherwise 0.

isvec()

Returns 1 if type or argument is a vector, otherwise 0.

vecindex()

vecindex(vector, value);

Source

Returns the index of value or nil, if value is not found in vector.

Example

var myvector = ["apple", "bananna", "coconut"];
# to check if a vector contains a certain value compare vecindex to nil
if (vecindex(myvector, "apple") != nil) {
    print("found apple");
}
# WARNING: this will not work as desired because index is 0
if (vecindex(myvector, "apple")) {
    print("found apple");
}

Variables

Various global constants (technically variables) are provided for use in converting between different units. They are all found in fgdata/Nasal/globals.nas.

D2R

var radians = degrees * D2R;

Converts an angle from degrees to radians when multiplied by the angle in degrees. Equal to π / 180.

FPS2KT

var knots = feet_per_second * FPS2KT;

Converts a velocity from feet per second to knots when multiplied by the velocity in feet per second. Approximately equal to 0.5925.

FT2M

var metres = feet * FT2M;

Converts a length from feet to metres when multiplied by the length in feet. Equal to 0.3048.

GAL2L

var litres = gallons * GAL2L;

Converts a volume from US liquid gallons to litres when multiplied by the volume in gallons. Approximately equal to 3.7854.

IN2M

var metres = inches * IN2M;

Converts a length from inches to metres when multiplied by the length in inches. Equal to 0.0254.

KG2LB

var pounds = kilograms * KG2LB;

Converts a mass from kilograms to pounds when multiplied by the mass in kilograms. Approximately equal to 2.2046.

KT2FPS

var feet_per_second = knots * KT2FPS;

Converts a velocity from knots to feet per second when multiplied by the velocity in knots. Approximately equal to 1.6878.

KT2MPS

var metres_per_second = knots * KT2MPS;

Converts a velocity from knots to metres per second when multiplied by the velocity in knots. Approximately equal to 0.5144.

L2GAL

var gallons = litres * L2GAL;

Converts a volume from litres to US liquid gallons when multiplied by the volume in litres. Approximately equal to 0.2642.

LB2KG

var kilograms = pounds * LB2KG;

Converts a mass from pounds to kilograms when multiplied by the mass in pounds. Approximately equal to 0.4536.

M2FT

var feet = metres * M2FT;

Converts a length from metres to feet when multiplied by the length in metres. Approximately equal to 3.2808.

M2IN

var inches = metres * M2IN;

Converts a length from metres to inches when multiplied by the length in metres. Approximately equal to 39.3701.

M2NM

var nautical_miles = metres * M2NM;

Converts a length from metres to nautical miles when multiplied by the length in metres. Approximately equal to 0.00054.

MPS2KT

var knots = metres_per_second * MPS2KT;

Converts a velocity from metres per second to knots when multiplied by the velocity in metres per second. Approximately equal to 1.9438.

NM2M

var metres = nautical_miles * NM2M;

Converts a length from nautical miles to metres when multiplied by the length in nautical miles. Equal to 1,852.

R2D

var degrees = radians * R2D;

Converts an angle from radians to degrees when multiplied by the angle in radians. Equal to 180 / π.

References