Script object

A script object is a way of organizing variables and functions that are related to an entity . It is analogous to a class in object orientated programming terms.

It’s uses are wide ranging from weapons and AI, to extending existing entities.

While an entities’ spawn class strongly defines run time behavior, script objects are generally used to create variation on run time behavior within that framework.

The spawn class sets up and runs a script object if the key/value pair “scriptobject” is set to a valid object type on the entities spawnArgs .

Working on objects

In order to call a function of a script object a valid object reference must be set up.

Example:

monster_base myMonster; 
myMonster = sys.getEntity("monster_sam"); /
myMonster.wake_on_trigger();

Line 1 declares and object reference of monster_base type. The script compiler will issue an error if there is no script object of that type.

Line 2 sets the reference to an entity. For the sake of this example we are assuming the entity “monster_sam” is an entity running a script object of they type monster_base, or one that inherits from monster_base.

An object reference will be set to $null_entity if the entity you are trying to set the variable to does not have a object of that type.

Line 3 calls the object function wake_on_trigger(), which we know is a function defined in the script object monster_base. If the function was not declared in the script object the script interpreter would issue a warning . TODO: find exact error/warning messages.

Declaration

Syntax:

object [script object type] : [base script object type] {
    [function declaration]
 
    [variable declaration]
    ...
}

Function Definition

Syntax:

[return type] [script object type]::[function name]([parameters]) {
   ...
}
  • [script object type] - The name of the object type. Must be unique within compiled script
  • [base script object type] - The object type to inherit from.
  • Function declarations - declared in the normal way. Referred to as an object function. See Scripting basics#Functions or Methods
  • Variable declarations - declared in the normal way. Referred to as a object variable. See Scripting basics#Variables

Important functions

A number of functions are called by the entitys spawn class .

init()

The script object constructor. A thread is created by the spawn class to run the init() script function at the end of the Spawn() function.

Use to set up initial state of the script object variables.

Note : There is a bug in the scripting system where the init() function won’t be able to call any functions of that object unless at least one variable is declared, or if the function in question is called through self .callFunction([function]);

destroy()

Destructor. Called early on in the spawn class destructor when the entity is removed.

Use to clean up anything that the script object was managing, such as created threads and entities.

Example

For this example the script object makes a light fade in and out for the life time of the entity. The time for the various stages is set up to be configurable via spawnArgs .

It’s a simple script, but we’ve tried to cram in as much important script object coding aspects as possible.

Script

You’ll see the currently broken note links to the example in the script, just look at the name of the link and find the note after the script.

TODO: find out if there is a way to escape wiki nonwikifying links in script/code tags.

To simplify things conceptually while working on a script we can think of the script object as being an entity that is running a script object of this type.

 
/***********************************************************************
 
light_strobe
A simple script object for use on entities of the spawn class idLight that fades in and out.
 
***********************************************************************/
 
object light_strobe { // [[#declare]]
    // declare functions
    void init();
    
    void main();
    
    // declare variables
    float fadeOutTime;
    float fadeInTime;
    float delayTime;
    
    boolean run;
};
 
/*
=====================
light_strobe::init
The first function called on entity spawn by the base spawn class
Use it to set up the initial state of the script object
=====================
*/
void light_strobe::init() {
    sys.println( sys.getTime() + " init()" ); // [[#debug print]]
    
    // [[#type check]]
    if ( getKey( "spawnclass" ) != "idLight" ) {
    // [[#warning]]
        sys.warning( "script object 'light_strobe' requires a the spawn class 'idLight', the entity it is running on '" + getName() + "' is of type '" + getKey( "spawnclass" ) + "'" );
        return; // [[#type check return]]
    }
 
    // set up variables
    // [[#spawnargs performance]]
    fadeOutTime = getFloatKey( "fade_in_time" );
    fadeInTime = getFloatKey( "fade_out_time" );
    delayTime = getFloatKey( "delay_time" );
    if ( delayTime == 0 ) {
        sys.warning( getName() + " - light_strobe - delay_time should be greater than 0" );
        delayTime = 1;
    }
    
    
    run = true; // we are using this to control our loop in main.
    
    // [[#run time function]]
    main();   
}
 
/*
=====================
light_strobe::main
=====================
*/
void light_strobe::main() {
    sys.println( sys.getTime() + " main()" ); // [[#debug print]]
    
    boolean isOn = true; // light starts on
 
    
    // [[#run time loop]]
    while( run ) { // we set run to true in init()
        sys.println( sys.getTime() + " loop top" ); // [[#debug print]]
        if ( isOn ) {
            //turnOff(); // [[#ETQW event]]
            fadeOutLight( fadeOutTime );
            //[[#functions on self]]
            isOn = false;
        } else {
            //turnOn(); // [[#ETQW event]]
            fadeInLight( fadeInTime );
            isOn = true;
        }
                
        sys.wait( delayTime );// [[#waiting]]
    }
}
 
// EOF

Entity set up

Put script in scripts folder and include in main script.

Set up on a light entity with the following key/value pairs:

"scriptobject" "light_strobe"
 
"delay_time" "2"
 
"fade_in_time" "3"
 
"fade_out_time" "1"

Note: While you could just add these keys to the map entity , setting up an entityDef for a spawn class/script object combination is the best way to set defaults for spawnArgs.

Example Notes

declare

Here we are declaring our script object type to be called light_strobe. object types must be unique, a search through the script files shows there isn’t any existing script object type called light_strobe.

debug print

Just to give an idea of what is going on while working on the script. The text will be shown in the console. Prefixing the game time is often handy to get an idea of the flow of the script.

type check

Since we will be using script events (event calls to the spawn class ) specific to an idLight spawn class we are doing some simple type checking to see if the entity this script object is running on is the right type.

getKey is an event defined in the base spawn class idEntity , so all spawn classes inherit it.

“spawnclass” is the key for the value in the spawnArgs dictionary that declares the spawn class.

This is the only way to check for spawn class type in script, since there is only one general reference type entity and object references types are only of script object type.

Note: since spawnArgs is a dictionary, accessing it is not as fast as operations on other data types, plus we are also doing a string comparing which is also an operation slower than operation on other data types, so this kind of type checking while useful, isn’t something that should be done per frame.

warning

We can decide how severe to be about this, here we are issuing a warning which will show in the console, if we wanted to be more strict we could call an Error to halt the game.

type check return

Stop script object from continuing further. This won’t prevent function calls on this script object, but in this case execution will stop before our run time logic starts.

spawnargs performance

As previously noted, variables are faster than spawnArgs access, so setting up variables with values from spawnArgs so they can be used later is a good idea.

run-time function

The base spawn class calls init() on start up, after init() is finished executing the script thread is considered ‘done’. The only code run on the object from that point would be from:

The spawn class calling a specific script function.

Another script thread calling a specific function.

In this object we are using a function called ‘main’ to do run time logic, so it must be the last operation before init() exits.

run time loop

Here we are trapping the function execution in a while loop, so the function doesn’t exit and we can keep our run time code running.

Once run time script object behavior gets to a certain point of complexity it’s better to plan a Finite State Machine .

ETQW event

Note: Enemy Territory: Quake Wars only:
Enemy Territory: Quake Wars does not have fadeIn and fadeOut events on the spawn class idLight, there are turnOn and turnOff events but as the names suggest, they do not fade over time.

functions on self

All function calls without a specific entity reference will be checked to see if it’s a function declared in the script object, or a script event on the the spawn class.

There is an equivalent way to call functions on the current entity that some prefer - self .[function].

fadeOut is an event defined in the spawn class idLight, if this script object were to run on an entity of a different spawn class it would produce a warning. At least it would if it ever got to this point, but the spawn class type check in init() prevents that.

waiting

Since we have trapped the function in a loop, at some point of execution we have to let the thread wait , otherwise the thread would continue indefinitely, preventing the rest of the game from continuing to run.

If we wanted code to be run per frame the only wait in our code would be a waitFrame() here at the end of the loop.