Scripting (Torque Script) : Concepts and Terminology
Scripting (Torque Script) : Concepts and Terminology
1
2
played, such partial-mods as: War 2002, Renegades, and Team Aerial Combat
(which started as a mod for Starseige Tribes).
Total-Mods If youve every played Half-Life, then you know what Im
talking about here. HL is without doubt the most MODed game of all time. In
addition to the thousands of partial-mods out there, you will find just as many (if
not more) new games, based on the HL engine, but written to a comptely different
genre using new models and new scripts.
Game Creation So, given total-mods, it isnt much of a stretch to imagine that
one could create an entire game via script. Id say that this not impossible, but a
bit of a stretch. For performance sake alone, I do not suggest this. However, if
performance is not your number one limiting factor, more power to you.
Features We Need
Given that we accept scripting is useful to us, what should we be looking for in a
scripting language? i.e. What functionality should it provide to us? As a bare minimum,
a scripting language, for use in a game, should provide the following features:
Familiar and Consistent Syntax Ideally, the syntax of the scripting language is
familiar, meaning it is similar to the syntax of a language we, as programmers, are
already familiar with, for example C or C++. Also ideal is that it be consistent,
meaning the same rules which apply to the familiar programming language also
apply to the scripting language.
Provides complete set of basic operations and constructs The scripting
language should provide a tool-kit of basic operations (addition, subtraction, etc).
Additionally, it should provide the standard constructs (if-then-else, for, while,
etc).
Provide access to Engine-Structures This is a critical feature. If the scripting
language is going to be of any use to us at all, it must provide some kind of
interface giving us a means of interacting with the engine and engine-structures.
In other words, we should have access to the render engine, we should be able to
create and delete objects, and we need complete control of and access to the I/O
sub-system.
Benefit/Drawback
Familiarity
Standard Language
(Ex: PERL)
Users are probably already
familiar with this.
Documentation
Engine integration
An important command well be using a lot is the echo() command. It has the following
basic syntax:
echo(string0 [, string1 [,...,[string n]]]);
Any statements in a box like the following can be cut and then pasted (CTRL + V) into
the console. Try these:
Hall Of Worlds, LLC. All rights reserved.
echo(Torque Rocks);
echo (1+1);
echo(16385 | 32768);
Convert the result of the last one to HEX (use a calculator if you must), and what do you
get? C001 !!!
Full complement of operators The complete list is in the appendix, but Torque
Scripts provides all the basic operators and a few advanced, including arithmetic,
relational, logical, bitwise, assignement, string, and access.
Functions Torque scrcipt provides the ability to create functions with the
optional ability to return values. Parameters are passed by-value and byreference. (see functions below for detailed description and examples.)
Compiles and executes PCODE As a bit of icing on the cake, the Torque
scripting engine compiles scripts prior to executing them, giving a speed increase
as well as providing a point at which errors in scripts can be reasonably found and
diagnosed.
Variables
Variables come in two flavors in Torque Script: Local and Global. Local
variables are transient, meaning they are destroyed automatically when they go out of
scope. Global variables, as you would expect, are permanent. The syntax is as follows:
%local_var = value;
$global_var = value2;
Variables do not need to be created before you use them. Just use them. If you
attempt to evaluate the value of a variable that was not previously created, it will be
created for you automatically.
for(0;%a<5;%a++) { echo(%a); };
echo(%a);
Note: The above code creates an error message on the first iteration, because the value
isnt created till the first time the loop completes. Also, %a is destroyed after the loop and
therefore we only print the value 4 once.
Variable names may contain any alpha-numeric (a..z, A..Z, 0..9), as well as the
underscore (_) but must start with an alpha- or an underscore. You may end variable
names with a numeric, but if you do, you must be especially careful with array names.
For further explanation, see of arrays below.
Lastly, local and global variables can have the same name, but contain different values.
$a=EGT:: ;
for(0;%a<5;%a++) { echo($a SPC %a); };
Data Types
Various types of data are supported by Torque script:
Numeric:
123
1.234
1234e-3
0xc001
(decimal)
(floating point)
(scientific notation)
(hexadecimal)
Nothing mysterious here. Torque Script handles your standard numeric types. I do
believe, floating point values are stored as 32-bit values (i.e. single-, not doubleprecision).
String:
abcd (string)
abcd (tagged string)
abc1234 (auto-string)
Standard strings, of the form value behave as you would expect. Try these
examples:
echo(Hello!);
echo(1.5 + 0.5);
Tagged strings are special in that they contain string data, but also have a special
numeric tag associated with them. Tagged strings are used for sending string data across
a network. The value of a tagged string is only sent once, regardless of how many times
you actually do the sending. On subsequent sends, only the tag value is sent. When
printing tagged values, you have untag them. Try these examples:
$a=This is a regular string;
$b=This is a tagged string;
echo( Regular string: SPC $a);
echo( Tagged string: SPC $b);
echo(Detagged string: SPC detag($b));
Note: You may find it odd that the last line shows a blank. This is because, although we
have created the tagged string, it has been transmitted to us. You can ONLY detag a
String Constant:
TAB
SPC
NL
(tab)
(space)
(newline)
There is an operator for string catenation @ in Torque Script. It has the basic
function of taking two strings and stitching them together. So some smart cookie,
probably at the behest of the script writers, added a few special string constants that
behave in the same way. The basic syntax for these string constants is:
string 1 op string 2
echo(Hi TAB there.);
echo(Hi SPC there.);
echo(Hi NL there.);
Escape Sequence:
\n
\r
\t
\c0\c9
\cr
\cp
\co
\xhh
\\
(newline)
(carriage return)
(tab)
(colorize subsequent text)
(reset to default color)
(push current color on color stack)
(pop color from color stack)
(two digit hex value ASCII code)
(backslash)
One of the cool and useful things that you dont find to this extent in all scripting
languages is escape sequences. As in C, you can create new-line and tabs using the
Boolean:
true
false
=> oops!);
(1)
(0)
Array:
$ary_Foo[n]
$ary_Bar[n,m]
$ary_Bar[n_m]
(Single-dimension)
(Multi-dimension)
(Multi-dimension)
CAUTION 2: $ary_myarray0 and $ary_myarray [0] are the same array. Yep, it may be
surprising, but Torque must figure you were lazy or something. I strongly suggest using
a naming convention to differentiate variable contents. To this day, although I know why
it is done, I still think it is bad..bad..bad practice to teach students to use i, j, k, etc. as
array indicies. See the example below for what could happen if you use variations of
these too-short and poorly named variables in your code.
$i0=0;
$i1[$i0]=$i0++;
$i1[$i0]=$i0++;
$i1[$i0]=$i0++;
Vector:
l m n o
(4 element vector)
Vectors are a cool pseudo data-type which you have probably been using
without even knowing it. Many fields in the inspector take numeric values in sets of 3 or
4. These are stored as strings and interpretted as vectors. There is a whole set of
console operations (read as available in scripts) for manipulating vectors. Also, as
mentioned, vectors are give as input to all kinds of game methods.
$vec_ray0 = 1.0 0.0 1.0;
$vec_ray1 = 1.0 6.0;
echo(VectorAdd($vec_ray0, $vec_ray1));
Note: Most vector functions only operate on vectors of three or fewer elements. Ive
added an appendix listing each function and showing pertinent usage details.
Operators
Because I think it would be both a waste of your time and mine to list data about
operators in both the body of this guide and in the appendix, Im going to refer you to
appendix EFM for operators. The only thing Ill discuss here is a few special (i.e. nonstandard) operations you might otherwise stumble over.
The ++ and -- operators are only post-fix operators (i.e. ++%a; does not work)
Separate comparison operations for numeric and string:
o Numeric comparisons are of the form:
==
!=
etc.
(numeric equal)
(numeric not-equal)
(See Appendix for remainder)
String catenation. You can concatenate (stitch together) strings using the
catenation operator.
Constructs
By constructs, I mean branching and looping structures. Torque Script supports
the following:
Branching Structures
if-then-else
The general structure of the if-then-else construct is:
if(expression) {
statements;
} else {
alternate statementss;
};
Things to know:
o brackets {} are optional for single line statements. (Suggestion:
always use them.)
o No, there is no then statement. It is implicit.
o Compound if-then-else-if-then- statements are perfectly legal
(Suggestion: Consider a switch statement for clarity sake.).
o Dont forget the semi-colon after the final bracket.
case valueN:
statements;
break;
default:
statements;
};
Things to know:
o switch only (correctly) evaluates numerics. There is a special
construct switch$ for strings.
o break statements are superfluous. Torque Script will only execute
matching cases.
o Dont forget the semicolon after the closing bracket.
o switch statements are not faster than if-then-else. (See EFM)
switch$ - This construct behaves exactly like the switch construct with one
important exeception. It is only for strings.
Looping Structures
for
The general structure of the for loop is:
echo(string0 [, string1 [,...,[string n]]]);
for(expression 0; expression1; expression2) {
statement(s);
};
Things to know:
o expression0 is usually of the form: var assign-op value (ex: $count =
0)
o You may use local variables for each expression. These expressions
will be automatically destroyed once the loop terminates.
for(%count=0;%count < 5; %count++) {
echo(%count);
}
echo(%count);
Console Functions
By definition, as a procedural language, Torque Script supports functions. Basic
console functions are defined as follows:
function func_name([arg0],...,[argn]) {
statements;
[return val;]
}
Console functions can take no arguments or any number of arguments separated
by commas. Also, a function may return an optional value.
Things to know:
Defining subsequent console functions with the same name as prior
console functions, over-rides the previous definition permanently unless
the re-definition is within a package (see packages below).
If you call a console function and pass fewer parameters than the console
function was defined with, unspecified parameters will be given an empty
string as their default value.
Objects
Having covered the basics of Torque Script let us examine some more interesting
details. In Torque, every item in the Game World is an object. Furthermore, all script
objects are created from C++ objects or datablocks. Examples would be: Player,
WheeledVehicle, TSStatic, etc.
Object Creation Syntax:
// In TorqueScript
%var = new ObjectType(Name : CopySource, arg0, , argn) {
<datablock = DatablockIdentifier;>
[existing_field0 = InitialValue0;]
...
[existing_field N = InitialValueN;]
[dynamic_field 0 = InitialValue0;]
...
[dynamic_field N = InitialValueN;]
};
new Is a key word telling the engine to create an instance of the following
ObjectType.
ObjectType Is any class declared in the engine (must be derived from
SimObject or a subclass of SimObject).
Name (optional) Is any expression evaluating to a string which will be used as
the objects name.
: CopySource (optional) EFM TBD Work out example for this.
GuiTextProfile is an example of this.
arg0, , argn (optional) Is a comma separated list of arguments to the class
constructor (if it takes any).
datablock Many objects (those derived from GameBase or children of
GameBase) require datablocks to initialize specific attributes of the new object.
Well discuss datablocks below.
existing_memberN In addition to initializing values with a datablock, you may
also initialize existing class members (fields) here.
o Note: Any member you wish to modify must have been exposed. Well
talk abou this later.
dynamic_memberN Lastly, you may create new fields (which will exist only in
Script) for your new object. These will show up as dynamic fields in the World
Editor Inspector.
Lets create one object that doesnt use a datablock and one that does:
// create a SimObject w/o modifying any fields
$example_object = new SimObject();
// create a SimObject w/ dynamic fields
$example_object = new SimObject() {
a_new_field = Hello world!;
};
// create a StaticShape using a datablock
// to run: exec(egt_base//datablock0.cs);
datablock StaticShapeData(MyFirstDataBlock) {
shapeFile = "~/data/shapes/player/player.dts";
junkvar = "helloworld";
};
new StaticShape() {
dataBlock = "MyFirstDataBlock";
position = "0.0 0.0 0.0";
rotation = "1 0 0 0";
scale = "1 1 1";
};
In most cases, Handles and names may be used interchangeably to refer to the same
object, but a word of caution is in order. Handles are always unique, whereas multiple
objects may have the same name. If you have multiple objects with the same name,
referencing that name will find one and only one of the objects. Generally, it is best to
use handles to refer to objects. This is faster anyway (name references require a lookup).
Dynamic Fields
In addition to normal fields, which are common between all instances of an object
type, Torque Script allows you to create dynamic fields. Dynamic fields are associated
with a single instance of an object and can be added and removed at will. Youve already
learned how to do this with the Inspector. Adding a dynamic field in Torque Script is
automatic. If you reference a field in the context of an object and the field is not found, it
will be created.
// new_var will be created and intialized to 0
echo($player_id.new_var);
// new_var2 will be created and intialized to Hello
$player_id.new_var2 = Hello;
echo($player_id.new_var2);
Console
Methods
At a minimum, Console Methods require that you pass them an object handle.
You will often see the first argument named %this. People use this as a hint, but you can
name it anything you want. As with console functions any number of additional
arguments can be specified, separated by commas. Also, a console method may return an
optional value.
Here are some examples:
function Goober::hi(%this) {
echo("Goober Hello ", %this);
}
we get,
<input> (0): Unknown command hi.
Object (1000) Player->ShapeBase->GameBase
->SceneObject->NetObject->SimObject
What has happened is that Torque has searched the entire hierarchy of Player and its
parent classes, looking for a function called hi() defined in the context of one of those
classes. Not finding one, it prints the above message. To demonstrate that Torque does
search the class hierarchy of Player, try this next:
function NetObject::hi(%this) {
echo("NetObject Hello ", %this);
}
typing,
1000.hi();
we get,
NetObject Hello 1000
Next, if we define:
function Player::hi(%this) {
echo("Player Hello ", %this);
we would type,
1000.hi();
and get,
Player Hello 1000
NetObject Hello 1000
Do you see what happened? Torque found Player:hi() first, but we also wanted to
execute the next previous defintion of hi(). To do this we used the Parent:: keyword.
Of course, not finding a ShapeBase instance, which is Players literal parent, Torque then
searched down the chain till it came to the NetObject version. Vioala!
Lastly, we can force Torque to call a specific instance as follows:
NetObject::hi(1000);
gives us,
NetObject Hello 1000
and
ShapeBase::hi(1000);
Packages
Packages provide dynamic function-polymorphism in Torque Script. In short, a
function defined in a package will over-ride the prior definition of a same named function
when the package is activated. Packages have the following syntax:
package package_name() {
function function_defition0() {
}
...
function function_defitionn() {
}
};
Things to know:
The same function can be defined in multiple packages.
Only functions can be packaged.
Datablocks (see below) cannot be packaged.
Packages are can be activated,
ActivatePackage(package_name);
and deactivated:
DeactivatePackage(package_name);
The easiest way to get a feel for packages is with a quick example. Assuming that
you have installed the EGT Lesson Kit (if not, see EFM), you can load the following
code from disk by typing this in the console:
exec(egt_base/samples/tech_scripting_packages01.cs);
//
// Define an initial function: demo()
//
function demo() {
echo("Demo definition 0");
}
//
// Now define three packages, each implementing
// a new instance of: demo()
//
package DemoPackage1 {
function demo() {
echo("Demo definition 1");
}
};
package DemoPackage2 {
function demo() {
echo("Demo definition 2");
}
};
package DemoPackage3 {
function demo() {
echo("Demo definition 3");
echo("Prior demo definition was=>");
Parent::demo();
}
};
//
// Finally, define some tests functions
//
function test_packages(%test_num) {
switch(%test_num) {
// Standard usage
case 0:
echo("----------------------------------------");
echo("A packaged function over-rides a prior");
echo("defintion of the function, but allows");
echo("the new definition to be \'popped\' ");
echo("off the stack.");
echo("----------------------------------------");
demo();
ActivatePackage(DemoPackage1);
demo();
ActivatePackage(DemoPackage2);
demo();
DeactivatePackage(DemoPackage2);
demo();
DeactivatePackage(DemoPackage1);
demo();
WARNING: Code is continued on next page (temporary fix for PDF bug that killed
remainder of table).
// Parents
case 1:
echo("----------------------------------------");
echo("The Parent for a packaged function is");
echo("always the previously activated ");
echo("packged function.");
echo("----------------------------------------");
demo();
ActivatePackage(DemoPackage1);
demo();
ActivatePackage(DemoPackage3);
demo();
DeactivatePackage(DemoPackage3);
DeactivatePackage(DemoPackage1);
echo("----------------------------------------");
demo();
ActivatePackage(DemoPackage1);
demo();
ActivatePackage(DemoPackage2);
demo();
ActivatePackage(DemoPackage3);
demo();
DeactivatePackage(DemoPackage3);
DeactivatePackage(DemoPackage2);
DeactivatePackage(DemoPackage1);
// Stacking oddities
case 2:
echo("----------------------------------------");
echo("Deactivating a \'tween\' package will");
echo("deactivate all packages \'stacked\' after");
echo("it.");
echo("----------------------------------------");
demo();
ActivatePackage(DemoPackage1);
demo();
ActivatePackage(DemoPackage2);
demo();
DeactivatePackage(DemoPackage1);
demo();
}
}
Namespaces
As previously mentioned, namespaces are provided in Torque Script. They way
they work is quite simple. First, all objects belong to a namespace. The namespace they
belong to normally defaults to the same name as the class.
// Player class Namespace
Player::
Also as previously mentioned, these namespaces provide separation of
functionality, such that one may have functions with the same name, but belonging to
separate namespaces. To use one of these functions, you must either manually select the
appropriate namespace, or in some cases this is done automatically for you. Ill readdress this below when we discuss console methods.
It is important to understand that the :: is not magical in any way. In fact, you
can create functions with :: in their name. This doesnt mean they belong to a
namespace. If the expression prefixing the :: is not a valid class/namespace name, in
effect, all you have done is create a unique name.
// Not really namespaces
function Ver1::doit() {
...
};
function Ver2::doit() {
...
};
Datablocks
Of all the features in Torque Script, Datablocks are probably the most confusing.
To make things worse, they are central to the creation of most objects, which means you
need to understand them relatively early. I will give a summary of datablocks here, but
because you need to understand some other more advanced topics prior to really jumping
into datablocks I will defer the in-depth review till later (see Datablocks Revisited
below).
The official definition of datablock is:
Datablocks are special objects that are used to transmit
static data from server to client.
- engine.overview.txt
In the words of Keanu Reeves himself, Whoaa. Or perhaps in my own
words, huh?. This definition, although true, didnt really tell me much. Some
searching turned up additional definitions:
A datablock is an object that contains a set of
characteristics which describe some other type of object.
- Joel Baxter
Better, but Im still a little blurry on the purpose and use of datablocks.
A datablock is a(n) object that can be declared either in
C++ engine code, or in script code ... Each declared
datablock can then be used as a template to create
objects...
- Liquid Creations, Scripting Tutorial #2
OK, now I get it. Datablocks are templates and we use them to create new
objects with the attributes specified by the template. Cool. But, how do we do this? For
the answer to that question, youll have to wait. First we need to discuss a few other
important topics, then we will revisit datablocks and give them the thorough coverage
that they deserve.
C++ Function
Member
Method
Local (Variable)
or
Global (Variable)
Console Function
Field
Dynamic Field
Command
(Deprecated)
Console Method
Definition
A C++ variable not associated with a class.
Solution
Solution Type
C++ to Console
Expose Member
as Field.
Expose Member
as Field.
Expose/Remove
global C++ Variable or
static Member
as Local Variable
Expose Method
as Command.
Create Console Method from C++.
Create Console Function from C++.
addField()
addFieldV()
addNamedField()
addNamedFieldV()
FUNCTION
MACRO
Con::addVariable()
Con::removeVariable()
FUNCTION
Con::addCommand()
(Deprecated)
FUNCTION
ConsoleMethod()
MACRO
ConsoleFunction()
MACRO
addField()
This function allows you to link C++ class members to console object fields.
The rules for using this function are:
1. Member to be exposed must be non-dynamic (i.e. not a pointer).
2. Member to be exposed must be non-static.
3. addField() statements must be included in the class initPersistFields() method.
void ConsoleObject::addField(const char* in_pFieldname,
const U32 in_fieldType,
const dsize_t in_fieldOffset,
const char* in_pFieldDocs)
void ConsoleObject::addField(const char* in_pFieldname,
const U32 in_fieldType,
const dsize_t in_fieldOffset,
const U32 in_elementCount,
EnumTable *in_table,
const char* in_pFieldDocs)
echo(####.damageFillColor);
####.damageFillColor = " 1.0 0.0 0.0 1.0";
echo(####.damageFillColor);
You may notice that although the contents of the variable were changed (to 100%
opaque RED), the reticle stayed GREEN. This is because you changed the Server-copy
of the variable, not the Client-copy. I will elaborate on this in the Networking chapter.
Having covered the most commonly used version of the addField() functions, lets quickly
outline the uses and syntax for the other varieties.
addFieldV()
This is a specialized version of the addField() function. It does not handle arrays
or ENUMs, but it has the nice feature of a validator function. Let us look at the syntax
and then Ill explain validator functions.
void ConsoleObject::addFieldV(const char* in_pFieldname,
const U32 in_fieldType,
const dsize_t in_fieldOffset,
TypeValidator *v)
Validator Functions
It is easiest to explain TypeValidators with some examples:
EFM
Offset() MACRO
I glossed over the Offset macro above in the interest of first discussing the usage
of addField() and its many versions. The offset macro is a cool bit of coding that
calculates the position of a variable within an instance of a class. Here is the syntax:
Offset(VariableName, ClassName)
removeField()
This function allows you to unlink a previously linked member-field pair. i.e.
This removes the field from the console. Simple as that. Why doit? Consider the case
where you derive from an object that does an addField() call for a member that you have
decided should not be accessible (like position for Terrain data).
bool ConsoleObject::removeField(const char* in_pFieldname)
Con::addVariable
This function allows you to expose a global C++ variable or a static Member as a
global variable in the console. see: camera.cc
Con::addVariable(const char *name, S32 t, void *dp);
// From camera.cc
Con::addVariable("Camera::movementSpeed",TypeF32,&mMovementSpeed);)
The above code exposes the global C++ variable mMovementSpeed in the
console as a global variable named Camera::movementSpeed.
Note: This controls the free camera flight speed while editting. Now you know another
way to set it beyond the normal editor keystrokes.
Con::removeVariable (deprecated)
This function allows you to remove a global variable from the console that was
previously added with one of the variants of the addVariable() function.
bool removeVariable(const char *name)
Upon searching, I found not a single instance in which this was used. This is
probably because it would be a sign of poor planning to add then remove a variable.
Having the source code, you could just remove the add call and be done with.
Nonetheless, you can use this function if it suits you to do so.
Con::addCommand (deprecated)
This function allows you to expose a Method as a Console Method. However, it
is now deprecated. i.e. You are not encouraged to use it. Instead, you should create a
method in C++ (if you need to use it in the engine), and then call this method from within
a ConsoleMethod (see below).
ConsoleMethod
This is a macro which allows you to create a new Console Method from C++.
The use of ConsoleMethod() is not much expanded in the engine as it has been chosen as
a means of replacing the more clumsy addCommand() calls. The static is used when
you want a want to create a console method that accesses/uses static class members.
ConsoleMethod(className,scriptname,returnType,minArgs,maxArgs,usage)
ConsoleStaticMethod(className,scriptname,returnType,minArgs,maxArgs,usage)
//From SimBase.cc
ConsoleMethod(SimObject, getId, S32, 2, 2, "obj.getId()")
{
argc; argv;
return object->getId();
}
In the above function, weve (well, the engine authors really) written a simple
utility to return the current objects unique ID (its handle). A short breakdown is as
follow:
It can be called on (by) all objects which are SimObjects or children of SimObject
The name of the function in Torque Script will be getId or more specifically
SimObject::getId.
getId takes two arguments, the ConsoleMethod name and the objects handle
(which by the way is the same thing were being asked to return).
The ConsoleMethod is expected to return a signed 32-bit value.
The ConsoleMethod will take a minimum and a maximum of two arguments.
The usage message is: obj.getId()
Internally,
o we do nothing with the standard argc and argv variables.
o we call a method named getId() to return a signed 32-bit value.
ConsoleFunction
This is a macro which allows you to create a new Console Function from C++.
Ex: ShapeBase.cc
ConsoleFunction(name,returnType,minArgs,maxArgs,usage)
name This is the name of the function as it will be used in the console.
returnType Is the return type of the function.
minArgs Minimum arguments this function can accept.
o Note: 1 Is the minimum, because the name of the function is
automatically passed as the first argument.
maxArgs Maximum arguments this function can accept.
o Note2: If you put 0 in this field, it means any number of arguments
may be passed to the function.
usage Is a string that will be printed as a help statement if someone later
attempts to use this function with the wrong number of arguments.
// From main.cc
ConsoleFunction( getSimTime, S32, 1, 1, "getSimTime() Time since game
started.")
{
return Sim::getCurrentTime();
}
First, I corrected the above consolefunction declaration for this example. In the
engine, the usage parameter was used instead to give information about the functions
purpose. Really, wed want it to tell us what to do if we messed up the args list. Its
pretty clear that this creates a function in the console named getSimtTime, which
returns a signed 32-bit value, and takes 1 argument. Interestingly, internally, we call the
static method Sim::getCurrentTime(). Remember, console functions can internally call
any function in the scope of the macros declaration or any static method.
Con::setLocalVariable()
This function allows you to set the contents of a local variable in the console from
within the engine. Note, all values passed as char strings to the console. The console
automatically converts this information as necessary.
Con::setLocalVariable(const char *name, const char *value);
Con::printf()
Con::warnf()
Con::errorf()
These functions provide the ability to print various levels of information into the
console (and subsequently the log if logging is enabled).
Datablocks Revisited
As previosly promised, we will now go into greater depth on the usage and
purpose of datablocks.
datablocks discussion
http://www.garagegames.com/index.php?sec=mg&mod=forums&page=result.forum&qt
m=datablock
EFM
Special Topics
Network Scripting
For a more detailed coverage of network scripting go to the networking chapter of
this guide.
Debugging Scripts
As with the other special topics, this will not be covered here. Instead, please go
to the debugging chapter.
EFM Add section detailing scripting tasks and section giving usage examples for script
available functions (as much as possible):
consolefunctions.cc
mathtypes.cc
sceneobject.cc
initContainerRadiusSearch and other goodies
shapebase.cc pointInWater, oncollision, ???