Expressions and Data References
|
Overview
Expressions in HeroScript are similar to most other programming languages. They can be anything from a simple number to a complex mathematical formula involving calls to other functions. They are only valid as parts of statements.
There are also various different kinds of data references in HeroScript. For example, how to access the data in a timer field, a subfield, and an array, all warrant some additional explanation, which is included on this page.
Literals
These are the ways of referencing different types of data.
- integer: 123
- float: 3.14, 0.23, .7
- time interval: interval: 0:30:00.000
- string: "hello"
- vector3: (1.0, 0.0, 0.0) ** as of HeroEngine 1.23
String tokens
There are also various string tokens such as the following:
-
$$
: Inserts a "$" character in a string -
$Q
: Inserts a double-quote " in a string -
$R
: Inserts a return character <cr> in a string -
$T
: Inserts a tab character in a string
System Variables
Please see the section on System Variables.
Node/Class Field References
Given that myVar is a variable of a type with a class that has field1, and field1 is of a class type that has field2, subfields are accessed as follows:
myVar.field1.field2
Timer field references
Given that n is a reference to a node, and that node has a class with the field exampleTimer of any timer type, the following fields may be retrieved:
n.exampleTimer.firstEnabled | Date Time |
n.exampleTimer.lastEnabled | Date Time |
n.exampleTimer.lastFired | Date Time |
n.exampleTimer.fireCount | Integer |
n.exampleTimer.enabled | Boolean |
n.exampleTimer.elapsed | Time Interval |
n.exampleTimer.remaining | Time Interval |
WallClockTimers have a fireTime field which can be read or set. It is a combination DateTime such as SYSTEM.TIME.NOW
. Other timers have an interval field which can be read or set to a TimeInterval.
The remaining field can be set to a Time Interval but only applies until the timer fires (does not change interval).
List References
Given that myVar is a variable of a list type, the following gives the first element of the list:
myvar[1]
Operators
Operator | Name | Operand data type(s) |
---|---|---|
+ | add | integer, float, string |
- | subtract | integer, float |
* | multiply | integer, float |
/ | divide | integer, float |
+= | add and assign | integer, float, string |
-= | subtract and assign | integer, float |
*= | multiply and assign | integer, float |
/= | divide and assign | integer, float |
not | logical inverse | boolean |
and | logical and | boolean |
or | logical or | boolean |
is exactly | test class on node | node - produces boolean |
is kindof | test class on node | node - produces boolean |
= or == | equal | integer, float, string, node, class, boolean - produces boolean |
> | greater than | integer, float, string - produces boolean |
>= | greater than or equal | integer, float, string - produces boolean |
< | less than | integer, float, string - produces boolean |
<= | less than or equal | integer, float, string - produces boolean |
!= or <> | not equal | produces boolean |
mod | produce remainder | modulus operator: returns the integer remainder |
& | ^ ~ << >> | bitwise operations | Same as C. See http://en.wikipedia.org/wiki/Bitwise_operation |
Operator Precedence
Expressions are processed from left to right, except in specific precedence cases.
Level | Operator | Name |
---|---|---|
highest | . | dot |
IS KINDOF IS EXACTLY |
||
not ~ - |
boolean "not" bitwise "not" unary negation | |
mod * / |
mod multiplication division | |
+ - |
addition subtraction | |
<< >> |
bit shift left bit shift right | |
has < > <= >= |
has less than greater than less than or equals greater than or equals | |
== != |
equals not equal to | |
& | bitwise "and" | |
^ | bitwise "exclusive or" | |
| | bitwise "or" | |
and | boolean "and" | |
or | boolean "or" | |
lowest | = += -= *= /= | assignment |
It is worth noting that in some cases, evaluation will stop before the entire expression is processed. For example, if there are multiple AND operators in an expression, which would all need to be TRUE simultaneously, then if any single one of them results as FALSE, the Here's Journey engine won't bother evaluating the others.
For example, suppose that trying to check the value of a field on a noderef will result in a script error if the NodeRef is None. So it is desirable to check that the node exists:
function demo (n as noderef of class x) if n != None then if n.name = "Bob" kill(n) . . .
A faster way to do this would be:
if n != None and n.name = "Bob" kill(n) .
So, even though checking n.name
would generate an error if n
was None, the engine won't get that far. However, writing the above statement as:
if n.name="Bob" and n!=None
then it *would* generate an error, since the engine would be evaluating the n.name
part first.
The same principle (processing stops when it becomes unnecessary) is true for the OR operator, except that it is reversed. For example, if there are multiple expressions being compared with OR, then the first one that returns a value of TRUE means that the rest can be skipped.
Examples
if i mod 7 . if x == 2 . if y <= 27 . if n is kindof ExampleClassName .
println("runLimit = "+SYSTEM.EXEC.RUNLIMIT.timeString) runLimit = 0:0:0.5