Variable Messages

Static Variables
Variables local to a user-defined function can now be made static (i.e., their values persist across invocations of the function) by prefacing the name of the variable with the characters "st_".

generic
{
  for(x = 0;x < 5;x++)
    docount();
}

docount
{
  if(!st_value)
    st_value = 0;

    info(++st_value);
}

Associative Assignments
You can assign multiple values to multiple variables by separating the variables with commas. For example:

main
{
  str = "23,-45,69.6,100,-.05,15.34";

  (p1,p2,p3,p4,p5,p6) = parse(",",str);

  info(p1," ",p2," ",p3);
}

You can also omit variables, so that only the variables specified are assigned to.

Example:
main
{
  str = "23,-45,69.6,100,-.05,15.34";

  (,p1,,p2,,p3) = parse(",",str);

  info(p1," ",p2," ",p3);
}

Inversely, you can omit values and nil will be assigned in their place, either in assignments, or in parameter passing to functions.

Example:
main
{
  testudf(,"Bob",,15.0,);
}

testudf: p1,p2,p3,p4,p5
{
  info(p1," ",p2," ",p3," ",p4," ",p5);
}

Default Assignments
Default value assignments can now be made on function argument parameters (much like C++). These default value assignments will trigger if the value passed to the function in that position is 'nil'.

Consider the following example:

main
{
  testudf(,"Bob",,15.0,);
}

testudf: p1 = -3.4,p2,p3 = "pretty",p4,p5
{
  info(p1," ",p2," ",p3," ",p4," ",p5);
}

This example script would print:

-3.4 Bob pretty 15 (nil)

If you wish to provide for an actual 'nil' value in your function's processing, then you must either avoid using default value assignments for that parameter, or use 'nil' as the default value.

main
{
testudf(,"Bob",,15.0,);
}

testudf: p1,p2,p3 = "pretty",p4,p5
{
if(p1) // if 'p1' == nil, nothing will print
info(p1," ",p2," ",p3," ",p4," ",p5);
}

Identifier Construction

Those identifiers used for variables and function names can now be "constructed" at run-time using a new language extension. This extension is triggered by using a "tick" mark or reverse apostrophe (`) found on the same key as the tilde.

Starting with a base identifier, you add constructors to the end, preceding each with the "tick" mark. For example, the following code fragment will assign the integer value 15 to the identifier "Bob36Hood":

. . .
x = 36;
y = "Hood";
Bob`x`y = 15;
. . .

When this code is executed, 'x' will contain 36, 'y' will hold "Hood", 'Bob' will be nil (ultimately, we are not assigning to 'Bob'), and the new variable 'Bob36Hood' will be 15.

Pseudo-arrays can be constructed by using this run-time identifier construction. However, this should only be used for low-count situations; otherwise, you should employ LScript's integral array support:

. . .
for(x = 1;x <= 10;x++)
value`x = x * x;
. . .

You can also use this mechanism to build function names (for invocation, NOT for definition):

. . .
reqbegin("Testing Identifier Construction");
c1 = ctlchoice("Which action?",1,
@"Action1","Action2","Action3"@);

if(!reqpost()) return;

x = getvalue(c1);
reqend();

func`x(); // evaluates to 'func1', 'func2' or 'func3'
. . .

Sequential Assignment
The LScript pre-processor supports a new sequential variable designator. The constructor is formed by surrounding an elipse ('..') with integer values that serve as the range of values to generate. The base variable name precedes the initial integer value, and is used to generate each declared variable.

For instance, this sequential veriable designator:

c1..5;

will be expanded by the pre-processor to:

c1,c2,c3,c4,c5;

Sequential variable designators can be used anywhere in your script code you would normally declare multiple variables. The following code, for example:

(lex1..5) = parse(" ",line);
info(lex1..5);

is functionally equivalent to:

(lex1,lex2,lex3,lex4,lex5) = parse(" ",line);
info(lex1,lex2,lex3,lex4,lex5);

Item ID information

Layout CS functions that expect an item id as their argument (such as SelectItem() or GoalItem()) will accept a varying combination of arguments to aid you in designating the needed Layout object.

- Integer values can be specified that are formatted as
they are in the LightWave scene file. These values
are hexidecimal, so some bit twiddling will be necessary
in order to place values in the correct locations of
the 32-bit integer:

// select the second Mesh object

SelectItem((1 << 28) | 1);

- A string value can be provided that should evaluate
to the name of an object in the current scene.

- An object class can be specified (MESH, LIGHT, CAMERA),
followed by an integer that specifies the linear offset
(1-based) of the object in the list of objects of that
class.

// select the third Light in the scene

SelectItem(LIGHT,3);

Object Masking
This mechanism allows objects of integral data types that support it to perform a "masking" operation on themselves. The exact result of this masking function will vary by the data type.

- Floating-point values (numbers, vectors) will use the masking value to render only that number of digits to the right of the decimal as significant.

- Character strings will use the masking value to return that number of characters from the left (equivalent to strleft()).

- All other data types will evaluate to themselves (i.e., masking is not applicable).

In order to mask an object, you follow the object operator ('.') with an integer value. For instance, the following code will print the value "1.34":

...
bob = 1.34398545;
info(bob.2);
...

Masking operators can only be used on variables.

Expression chaining can also be used:

...
bob = 1.34398545;
info(bob.2.asStr().isStr()); // prints 1
...

Global Constants

SCRIPTID
A global constant value called SCRIPTID exists in the LScript operating environment. This constant holds the full path and filename of the script currently being executed.

Integral data types (integers, numbers, strings, etc.) respond to the following set of methods:

Methods

size
size()returns the size of the item.

<integer>       returns the value itself.

<number>      returns the value itself.

<string>        returns the number of characters.

<vector>        returns 1.

<array>         returns the total elements allocated.

count()
count() returns the count of the item.

<integer>      returns 1.

<number>     returns 1.

<vector>       returns 1.

<string>       returns number of characters.

<array>   returns number of elements that contain values.

The count() method can now be provided a character argument when applied to string-type objects.When provided, the number of occurances of that character will be returned
  to the caller as an integer.
        ...
        s = "1:2:5:38";
        info(s.count(':'));   // displays 3
        ...


contains()
This method is now available for integral data types that will, given a data type and value, search through indexable types (arrays, strings, etc.) to determine if that type and value exists. It returns a Boolean true/false value to indicate the presence or absence, respectively, of the provided value.
...
str = "Now is the time";
info(str.contains("is the")); // displays true (1)
info(str.contains("Bob")); // displays false (0)
...

...
t = @15.87,"Blowfish",<1,9,0.5>@;
info(t.contains(<1,9,0.5>)); // displays true (1)
info(t.contains(15.87)); // displays true (1)
info(t.contains("Blow")); // displays false (0) 

...

asInt()
asInt() returns the data interpreted as an integer.


asNum()
asNum() returns the data interpreted as a number.

asStr()
asStr() returns the data interpreted as a character string.

The asStr() method can now be applied to linear arrays.  Supported data types will be
  concatenated into a single string value.  Elements of 'nil' value are ignored.  You can
  provide an optional character value that will be used to separate values added to the
  string.

        ...
        a[1] = "val1";
        a[2] = 15;
        a[3] = nil;
        a[4] = 3.14;
        info(a.asStr(':'));     // displays "val1:15:3.14"
        ...

asVec()
asVec() returns the data interpreted as a vector.

asAsc()
asAsc() returns the integer provided interpreted as a character.

if(line[x].asAsc == '\t')
...

asBin()
asBin() returns the integer ASCII value of a character provided to it.

pack()
pack() packs the data and returns a Boolean true or false to indicate whether or not packing occured.

<integer>      does nothing.

<number>     does nothing.

<vector>       does nothing.

<string>       removes leading white space.

<array>       packs elements with values down to removeintervening 'nil' values.

It also handles associative arrays.

trunc()
trunc() truncates the data and returns a Boolean true or false value to indicate whether or not truncating took place.

<integer>      does nothing.

<number>     does nothing.

<vector>      does nothing.

<string>      removes trailing white space.

<array>      resizes the array, removing trailing elements whose value is 'nil'.

sortA()
sorts the data in ascending order and returns a boolean true or false value to indicate whether or not sorting took place.

<integer>      does nothing.

<number>     does nothing.

<vector>       does nothing.

<string>        sorts characters in ascending order.

<array>        packs, then sorts like elements in ascending order.

                   Integer, number and string are sortable.

sortD()
sorts the data in descending order and returns a boolean true or false to indicate whether or not sorting took place.

<integer>      does nothing.

<number>     does nothing.

<vector>       does nothing.

<string>       sorts characters in ascending order.

<array>        packs, then sorts like elements in descending order.

                    Integer, number and string are sortable.

keys()
This method can be applied to an associative array to extract all keys contained
within the array. This allows a script to access all data elements contained in the
associative array in a linear fashion.

isNil()
isNil() tests the data type for 'nil' and returns a Boolean true or false. Functionally equivalent to performing an equality test (e.g., "data == nil").

isInt()
isInt() tests the data type for integer and returns a Boolean true or false. There is no equality test equivalent.

isNum()
isNum() tests the data type for number and returns a Boolean true or false. There is no equality test equivalent.

isStr()
isStr() tests the data type for string and returns a Boolean true or false value. There is no equality test equivalent.

isVec()
isVec() tests the data type for vector and returns a Boolean true or false value. There is no equality test equivalent.

isPrint()
Test the character for printability.

isAlpha()
Test the character for membership in the alphabetic class (i.e., a-z or A-Z).

isAlnum()
Test the character for membership in the alpha-numeric class.

isAscii()
Test the character for membership in the ASCII character set.

isCntrl()
Test the character for membership in the control code character set.

isDigit()
Test the character for membership in the numeric character set (i.e., 0-9).

isPunct()
Test the character for membership in the punctuation character set (i.e., any printable character that is not a space character, or a character for which isAlnum() returns true).

isSpace()
Test the character as whitespace (i.e., a space character, or character in the range 0x090x0D).

isUpper()
Test the character for membership in the upper-case alphabetic character set.

isLower()
Test the character for membership in the lower-case alphabetic character set.

isXDigit()
Test the character for membership in the hexidecimal character set (i.e., one of "0123456789ABCDEF").

indexOf()
indexOf() can be applied to string, linear array and binary block data types. This method can be used to locate data within these indexable types. The method returns the index where the specified data is found. If it is not found, then a value of zero (0) is returned.

In the case of character strings, the provided search value is treated as a displayable character:

...
s = "val1:15:3.14";
ndx = s.indexOf(':'); // returns 5
...

For linear arrays, the value provided must match an element in both type and value in order to be considered a successful match. Not all data types are supported for searching.

Searches through binary data will treat the provided integer value as an unsigned character, and should be in the range 0 to 255.

By default, searches begin at the initial index offset of one (1). You can specify a beginning offset other than one by providing the integer offset before the search value.

...
s = "val1:15:3.14";
ndx = s.indexOf(':'); // returns 5
ndx = s.indexOf(ndx + 1,':'); // returns 8
...

reduce()
The reduce()method will remove duplicate values from the data type (useful mostly for strings and arrays). Duplicate values are expected to be in linear order—that is, adjacent to one another. You should probably employ one of the sort methods before invoking reduce().

The following is an example of using the reduce() method. A linear series of Polygon identifiers are gathered into an array in a situation where there is a high probablity of duplication. Subsequent calls to sortA() and reduce() remove any duplicate entries from the resulting array:

for(x = 1;x <= pointCnt;x++)
{
    rawPolys = points[x].polygon();
    polyCnt = rawPolys.count();

     for(y = 1;y <= polyCnt;y++)
         polySelect += rawPolys[y];
}

polySelect.sortA();
polySelect.reduce();

Examples

The following code fragment creates an array of eight elements, and then places values within it at random. A pack() and a trunc() are then performed on the array:

q[8] = nil;
q[2] = 1.5;
q[4] = "Bob";
q[5] = <1,2,3>;

info(q.size());
info(q.count());
info(q);

q.pack();
info(q);

q.trunc();
info(q);

This script code would print the following messages:

8

3

(nil) 1.5 (nil) "Bob" <1,2,3> (nil) (nil) (nil)

1.5 "Bob" <1,2,3> (nil) (nil) (nil) (nil) (nil)

1.5 "Bob" <1,2,3>

While all data types respond to each message, not all operations have meaning. For instance, packing or truncating an integer does nothing.

String Commands

hash
This method, useful only with character strings, will return an integer value that represents a calculated hash value for that string. The array type also responds to this method, and will calculate a hash value for all string elements in the array.

mystring="Blah";
mike=mystring.hash();
StatusMsg(mike.asStr());

split
split() works specifically with file path/name character strings. It accepts a character string, and returns an array of four elements representing the drive, path, filename, and filename extension that could be derived from the string argument.

file = getfile(“Select A Scene...”,”*.lws”);
if(file == nil)
    return;
if(fileexists(file))
{
    base = split(file);
    // get the components (base becomes an array)

Components of the string that do not exist (i.e., no drive designation) are returned as nil.

strleft
The strleft() function returns a portion of a character string beginning from the left. It accepts two parameters, where the first is the character string to be processed, and the second is a number of characters to extract.

value = strleft(“This string.”,3);
//result: “Thi”

strright
The strright() function returns a portion of a character string beginning from the right. It accepts two parameters, where the first is the character string to be processed, and the second is a number of characters to extract.

value = strright(“This string.”,3);
… //result: “ng.”

strsub
strsub() is string extraction function. This function lets you extract an arbitrary number of characters from within the string starting from an arbitrary location, instead of starting from one of its ends.

t = strsub(“Ted Philmore”,3,5); // returns: “d Phi”

strupper
The strupper() function returns a copy of the provided string in upper-case characters.

value = strupper(“upper-case”); //returns: UPPER-CASE

strlower
The strlower() function returns a copy of the provided string in lower-case characters.

value = strupper(“LOWER-CASE”);//returns: lower-case

parse
parse() accepts two parameters: the first is a string of potential token separators and the second is the character string to process. This function returns an array of tokens that make up the string (second parameter).

str = “23,45,69.6,100”;
tokens = parse(“,”,str);
// returns “23”, “45”, “69.9” and “100”

format
A format() function can format a string by performing token substitution within the string with provided values. This is much like C’s printf() function. It can be used with individual data elements, but it is intended for arrays.

format(<template>,<data>[,<data>...])

Tokens are indicated by a dollar sign ($) followed by the numeric index value to be taken from the arguments provided. Index value need not be sequential, nor must you access all elements.

Individual arguments can be either a list of single data types (variables or constants), or you can provide a single array value to the used in the substitution. You cannot provide both.

The function returns a string value that has all substitutions performed:

d = date();
info(format(“Today is $7, $6 $1, $3”,d));
(h,m) = time();

ap = “AM”;
if(h > 11)
{
    ap = “PM”;
    h -= 12 if h > 12;
}
h = 12 if h == 0;
info(format(“Time is currently $1:$2” + ap,h,m));

General Commands

store
The store command lets a script retain variable values across invocations. The store() command takes two parameters: the first parameter is a string literal (or variable with a character string) that uniquely identifies the value to be stored, and the second parameter is the actual value itself.

store(“myName”,myName);

recall
The recall command lets a script retain variable values across invocations. recall() retrieves values that have been previously store()’d. As with store(), it also takes two parameters. The first parameter is the value identifier that was originally used to retain the value. The second parameter is a default value to return if a store() has never been issued for that identifier.

heading = recall(“heading”,15);

globalstore
The globalstore() function works the same as the store() command, however it functions across different scripts of the same architecture.

globalstore(“heading”, 23);

globalrecall
The globalrecall() function works the same as the recall() command, however it functions across different scripts.

heading = globalrecall(“heading”, 8);

size command
The size() command determines the size of a particular variable of a particular data type. For numeric values, it returns 1. For vector types, it returns 3. Character string arguments return the number of characters in the string, while array arguments return the number of actual elements in the array (not the total size of the array).

str = “23,45,69.6,100”;
tokens[10] = nil;
t = size(tokens); // returns 0
tokens = parse(“,”,str); // returns four elements
t = size(tokens); // returns 4
tokens[8] = 1.0;
t = size(tokens); // returns 5

sizeof
The sizeof() function returns the size of an array.

tmp[1] = 1;
tmp[2] = 2;
tmp[3] = 3;
info(sizeof(tmp));